diff --git a/.github/AL-Go-Settings.json b/.github/AL-Go-Settings.json index d8828d5a876..60bb867acb2 100644 --- a/.github/AL-Go-Settings.json +++ b/.github/AL-Go-Settings.json @@ -2,7 +2,7 @@ "$schema": "https://raw.githubusercontent.com/microsoft/AL-Go/91b96c2b294be6f823277dafe6f03350abfb9d23/Actions/.Modules/settings.schema.json", "type": "PTE", "templateUrl": "https://github.com/microsoft/AL-Go-PTE@preview", - "bcContainerHelperVersion": "preview", + "bcContainerHelperVersion": "6.1.19-preview2811389", "runs-on": "windows-latest", "cacheImageName": "", "UsePsSession": true, @@ -15,6 +15,7 @@ "repoVersion": "30.0", "memoryLimit": "16G", "numberOfTenantsForTesting": 4, + "enableCleanTestCodeunitExecution": true, "maxTestAppReruns": 2, "failOn": "newWarning", "workspaceCompilation": { diff --git a/.github/workflows/CICD.yaml b/.github/workflows/CICD.yaml index 4c650a3d64b..083434e58da 100644 --- a/.github/workflows/CICD.yaml +++ b/.github/workflows/CICD.yaml @@ -1,453 +1,96 @@ -name: ' CI/CD' +name: 'SQL platform fix uptake - DO NOT MERGE' +run-name: SQL platform 30.0.56092.0 - ten original control cells on: workflow_dispatch: - push: - paths-ignore: - - '**.md' - - '.github/workflows/*.yaml' - - '!.github/workflows/CICD.yaml' - branches: [ 'main', 'releases/*' ] - -defaults: - run: - shell: powershell + inputs: + authorization: + description: Exact authorization AB653457-fixed-platform-original-control-10 + type: string + required: true permissions: actions: read contents: read id-token: write - pages: read - security-events: write packages: read -env: - workflowDepth: 2 - ALGoOrgSettings: ${{ vars.ALGoOrgSettings }} - ALGoRepoSettings: ${{ vars.ALGoRepoSettings }} +concurrency: + group: sql-platform-653457-fixed-uptake + cancel-in-progress: false jobs: - Initialization: - needs: [ ] - runs-on: [ windows-latest ] + Plan: + if: github.repository == 'microsoft/BCApps' && github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/features/653457-sql-platform-fix-uptake' && github.run_attempt == 1 && inputs.authorization == 'AB653457-fixed-platform-original-control-10' + runs-on: windows-latest + timeout-minutes: 10 outputs: - telemetryScopeJson: ${{ steps.init.outputs.telemetryScopeJson }} - environmentsMatrixJson: ${{ steps.DetermineDeploymentEnvironments.outputs.EnvironmentsMatrixJson }} - environmentCount: ${{ steps.DetermineDeploymentEnvironments.outputs.EnvironmentCount }} - deploymentEnvironmentsJson: ${{ steps.DetermineDeploymentEnvironments.outputs.DeploymentEnvironmentsJson }} - generateALDocArtifact: ${{ steps.DetermineDeploymentEnvironments.outputs.GenerateALDocArtifact }} - deployALDocArtifact: ${{ steps.DetermineDeploymentEnvironments.outputs.DeployALDocArtifact }} - deliveryTargetsJson: ${{ steps.DetermineDeliveryTargets.outputs.DeliveryTargetsJson }} - githubRunner: ${{ steps.ReadSettings.outputs.GitHubRunnerJson }} - githubRunnerShell: ${{ steps.ReadSettings.outputs.GitHubRunnerShell }} - projects: ${{ steps.determineProjectsToBuild.outputs.ProjectsJson }} - skippedProjects: ${{ steps.determineProjectsToBuild.outputs.SkippedProjectsJson }} - projectDependenciesJson: ${{ steps.determineProjectsToBuild.outputs.ProjectDependenciesJson }} - buildOrderJson: ${{ steps.determineProjectsToBuild.outputs.BuildOrderJson }} - baselineWorkflowRunId: ${{ steps.determineProjectsToBuild.outputs.BaselineWorkflowRunId }} - baselineWorkflowSHA: ${{ steps.determineProjectsToBuild.outputs.BaselineWorkflowSHA }} - workflowDepth: ${{ steps.DetermineWorkflowDepth.outputs.WorkflowDepth }} - powerPlatformSolutionFolder: ${{ steps.DeterminePowerPlatformSolutionFolder.outputs.powerPlatformSolutionFolder }} - trackALAlertsInGitHub: ${{ steps.SetALCodeAnalysisVar.outputs.trackALAlertsInGitHub }} - steps: - - name: Dump Workflow Information - uses: microsoft/AL-Go/Actions/DumpWorkflowInfo@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - lfs: true - - - name: Initialize the workflow - id: init - uses: microsoft/AL-Go/Actions/WorkflowInitialize@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - - - name: Read settings - id: ReadSettings - uses: microsoft/AL-Go/Actions/ReadSettings@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - get: type,powerPlatformSolutionFolder,useGitSubmodules,trackALAlertsInGitHub - - - name: Set AL Code Analysis Var output - id: SetALCodeAnalysisVar - run: | - Write-Host "trackALAlertsInGitHub environment variable: '$($env:trackALAlertsInGitHub)'" - Add-Content -Encoding UTF8 -Path $env:GITHUB_OUTPUT -Value "trackALAlertsInGitHub=$($env:trackALAlertsInGitHub)" - - - name: Read submodules token - id: ReadSubmodulesToken - if: env.useGitSubmodules != 'false' && env.useGitSubmodules != '' - uses: microsoft/AL-Go/Actions/ReadSecrets@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - gitHubSecrets: ${{ toJson(secrets) }} - getSecrets: '-gitSubmodulesToken' - - - name: Checkout Submodules - if: env.useGitSubmodules != 'false' && env.useGitSubmodules != '' - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - lfs: true - submodules: ${{ env.useGitSubmodules }} - token: '${{ fromJson(steps.ReadSubmodulesToken.outputs.Secrets).gitSubmodulesToken }}' - - - name: Determine Workflow Depth - id: DetermineWorkflowDepth - run: | - Add-Content -Encoding UTF8 -Path $env:GITHUB_OUTPUT -Value "WorkflowDepth=$($env:workflowDepth)" - - - name: Determine Projects To Build - id: determineProjectsToBuild - uses: microsoft/AL-Go/Actions/DetermineProjectsToBuild@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - maxBuildDepth: ${{ env.workflowDepth }} - - - name: Determine PowerPlatform Solution Folder - id: DeterminePowerPlatformSolutionFolder - if: env.type == 'PTE' - run: | - Add-Content -Encoding UTF8 -Path $env:GITHUB_OUTPUT -Value "powerPlatformSolutionFolder=$($env:powerPlatformSolutionFolder)" - - - name: Determine Delivery Target Secrets - id: DetermineDeliveryTargetSecrets - uses: microsoft/AL-Go/Actions/DetermineDeliveryTargets@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - projectsJson: '${{ steps.determineProjectsToBuild.outputs.ProjectsJson }}' - checkContextSecrets: 'false' - - - name: Read secrets - id: ReadSecrets - uses: microsoft/AL-Go/Actions/ReadSecrets@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - gitHubSecrets: ${{ toJson(secrets) }} - getSecrets: ${{ steps.DetermineDeliveryTargetSecrets.outputs.ContextSecrets }} - - - name: Determine Delivery Targets - id: DetermineDeliveryTargets - uses: microsoft/AL-Go/Actions/DetermineDeliveryTargets@91b96c2b294be6f823277dafe6f03350abfb9d23 - env: - Secrets: '${{ steps.ReadSecrets.outputs.Secrets }}' - with: - shell: powershell - projectsJson: '${{ steps.determineProjectsToBuild.outputs.ProjectsJson }}' - checkContextSecrets: 'true' - - - name: Determine Deployment Environments - id: DetermineDeploymentEnvironments - uses: microsoft/AL-Go/Actions/DetermineDeploymentEnvironments@91b96c2b294be6f823277dafe6f03350abfb9d23 - env: - GITHUB_TOKEN: ${{ github.token }} - with: - shell: powershell - getEnvironments: '*' - type: 'CD' - - CheckForUpdates: - needs: [ Initialization ] - runs-on: [ windows-latest ] + batch01: ${{ steps.plan.outputs.batch01 }} + batch02: ${{ steps.plan.outputs.batch02 }} + batch03: ${{ steps.plan.outputs.batch03 }} + batch04: ${{ steps.plan.outputs.batch04 }} + batch05: ${{ steps.plan.outputs.batch05 }} steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Read settings - uses: microsoft/AL-Go/Actions/ReadSettings@91b96c2b294be6f823277dafe6f03350abfb9d23 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: - shell: powershell - get: templateUrl - - - name: Read secrets - id: ReadSecrets - uses: microsoft/AL-Go/Actions/ReadSecrets@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - gitHubSecrets: ${{ toJson(secrets) }} - getSecrets: 'ghTokenWorkflow' - - - name: Check for updates to AL-Go system files - uses: microsoft/AL-Go/Actions/CheckForUpdates@91b96c2b294be6f823277dafe6f03350abfb9d23 + fetch-depth: 0 + - name: Verify original package transport and canonical fixed-runtime plan + id: plan + shell: pwsh env: - GITHUB_TOKEN: ${{ github.token }} - with: - shell: powershell - templateUrl: ${{ env.templateUrl }} - token: ${{ fromJson(steps.ReadSecrets.outputs.Secrets).ghTokenWorkflow }} - downloadLatest: true - - Build1: - needs: [ Initialization ] - if: (!failure()) && (!cancelled()) && fromJson(needs.Initialization.outputs.buildOrderJson)[0].projectsCount > 0 - strategy: - matrix: - include: ${{ fromJson(needs.Initialization.outputs.buildOrderJson)[0].buildDimensions }} - fail-fast: false - name: Build ${{ matrix.projectName }} (${{ matrix.buildMode }}) - uses: ./.github/workflows/_BuildALGoProject.yaml + GH_TOKEN: ${{ github.token }} + BC_SQL_UPTAKE_AUTHORIZATION: ${{ inputs.authorization }} + run: .\build\scripts\SqlResetPilot\PlanPlatformUptake.ps1 + - name: Preserve scheduling and package provenance + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + with: + name: sql-platform-uptake-manifest-${{ github.run_id }} + retention-days: 14 + if-no-files-found: error + include-hidden-files: true + path: .sql-api-comparison-plan/*.json + + Batch01: + needs: Plan + uses: ./.github/workflows/SqlApiComparisonBatch.yaml secrets: inherit with: - shell: ${{ matrix.githubRunnerShell }} - runsOn: ${{ matrix.githubRunner }} - project: ${{ matrix.project }} - projectName: ${{ matrix.projectName }} - buildMode: ${{ matrix.buildMode }} - skippedProjectsJson: ${{ needs.Initialization.outputs.skippedProjects }} - projectDependenciesJson: ${{ needs.Initialization.outputs.projectDependenciesJson }} - baselineWorkflowRunId: ${{ needs.Initialization.outputs.baselineWorkflowRunId }} - baselineWorkflowSHA: ${{ needs.Initialization.outputs.baselineWorkflowSHA }} - secrets: 'licenseFileUrl,codeSignCertificateUrl,*codeSignCertificatePassword,keyVaultCertificateUrl,*keyVaultCertificatePassword,keyVaultClientId,gitHubPackagesContext,applicationInsightsConnectionString' - signArtifacts: true - useArtifactCache: true - needsContext: ${{ toJson(needs) }} + matrix: ${{ needs.Plan.outputs.batch01 }} + authorization: ${{ inputs.authorization }} - Build: - needs: [ Initialization, Build1 ] - if: (!failure()) && (!cancelled()) && (needs.Build1.result == 'success' || needs.Build1.result == 'skipped') && fromJson(needs.Initialization.outputs.buildOrderJson)[1].projectsCount > 0 - strategy: - matrix: - include: ${{ fromJson(needs.Initialization.outputs.buildOrderJson)[1].buildDimensions }} - fail-fast: false - name: Build ${{ matrix.projectName }} (${{ matrix.buildMode }}) - uses: ./.github/workflows/_BuildALGoProject.yaml + Batch02: + needs: [Plan, Batch01] + if: always() && !cancelled() && needs.Plan.result == 'success' + uses: ./.github/workflows/SqlApiComparisonBatch.yaml secrets: inherit with: - shell: ${{ matrix.githubRunnerShell }} - runsOn: ${{ matrix.githubRunner }} - project: ${{ matrix.project }} - projectName: ${{ matrix.projectName }} - buildMode: ${{ matrix.buildMode }} - skippedProjectsJson: ${{ needs.Initialization.outputs.skippedProjects }} - projectDependenciesJson: ${{ needs.Initialization.outputs.projectDependenciesJson }} - baselineWorkflowRunId: ${{ needs.Initialization.outputs.baselineWorkflowRunId }} - baselineWorkflowSHA: ${{ needs.Initialization.outputs.baselineWorkflowSHA }} - secrets: 'licenseFileUrl,codeSignCertificateUrl,*codeSignCertificatePassword,keyVaultCertificateUrl,*keyVaultCertificatePassword,keyVaultClientId,gitHubPackagesContext,applicationInsightsConnectionString' - signArtifacts: true - useArtifactCache: true - needsContext: ${{ toJson(needs) }} - - CodeAnalysisUpload: - needs: [ Initialization, Build ] - if: (!cancelled()) && (needs.Initialization.outputs.trackALAlertsInGitHub == 'True') - runs-on: [ windows-latest ] - name: Code Analysis Processing - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Download artifacts - ErrorLogs - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - env: - ACTIONS_RUNNER_DISABLE_NODE_MAGLEV: 1 - if: (success() || failure()) - with: - pattern: '*-*ErrorLogs-*' - path: '${{ github.workspace }}/ErrorLogs/' - merge-multiple: true - - - name: Process AL Code Analysis Logs - id: ProcessALCodeAnalysisLogs - if: (success() || failure()) - uses: microsoft/AL-Go/Actions/ProcessALCodeAnalysisLogs@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell + matrix: ${{ needs.Plan.outputs.batch02 }} + authorization: ${{ inputs.authorization }} - - name: Upload SARIF file to GitHub - uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 - if: (success() || failure()) && (hashFiles(format('{0}/ErrorLogs/output.sarif.json',github.workspace)) != '') - with: - sarif_file: '${{ github.workspace }}/ErrorLogs/output.sarif.json' - category: "ALCodeAnalysis" - - DeployALDoc: - needs: [ Initialization, Build ] - if: (!cancelled()) && (needs.Build.result == 'success' || needs.Build.result == 'skipped') && needs.Initialization.outputs.generateALDocArtifact == 1 && github.ref_name == 'main' - runs-on: [ windows-latest ] - name: Deploy Reference Documentation - permissions: - contents: read - actions: read - pages: write - id-token: write - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Download artifacts - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - env: - ACTIONS_RUNNER_DISABLE_NODE_MAGLEV: 1 - with: - path: '.artifacts' - - - name: Read settings - uses: microsoft/AL-Go/Actions/ReadSettings@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - - - name: Determine ArtifactUrl - id: determineArtifactUrl - uses: microsoft/AL-Go/Actions/DetermineArtifactUrl@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - - - name: Setup Pages - if: needs.Initialization.outputs.deployALDocArtifact == 1 - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - - - name: Build Reference Documentation - uses: microsoft/AL-Go/Actions/BuildReferenceDocumentation@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - artifacts: '.artifacts' - artifactUrl: ${{ env.artifact }} - - - name: Upload pages artifact - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 - with: - path: ".aldoc/_site/" - - - name: Deploy to GitHub Pages - if: needs.Initialization.outputs.deployALDocArtifact == 1 - id: deployment - uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 - - Deploy: - needs: [ Initialization, Build1, Build ] - if: (!cancelled()) && (needs.Build1.result == 'success' || needs.Build1.result == 'skipped') && (needs.Build.result == 'success' || needs.Build.result == 'skipped') && needs.Initialization.outputs.environmentCount > 0 - strategy: ${{ fromJson(needs.Initialization.outputs.environmentsMatrixJson) }} - runs-on: ${{ fromJson(matrix.os) }} - name: Deploy to ${{ matrix.environment }} - defaults: - run: - shell: ${{ matrix.shell }} - environment: - name: ${{ matrix.environment }} - url: ${{ steps.Deploy.outputs.environmentUrl }} - env: - ALGoEnvSettings: ${{ vars.ALGoEnvironmentSettings }} - ALGoEnvName: ${{ matrix.environment }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Download artifacts - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - env: - ACTIONS_RUNNER_DISABLE_NODE_MAGLEV: 1 - with: - path: '.artifacts' - - - name: Read settings - uses: microsoft/AL-Go/Actions/ReadSettings@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: ${{ matrix.shell }} - get: type,powerPlatformSolutionFolder - - - name: EnvName - id: envName - run: | - $errorActionPreference = "Stop"; $ProgressPreference = "SilentlyContinue"; Set-StrictMode -Version 2.0 - $envName = '${{ matrix.environment }}'.split(' ')[0] - Add-Content -Encoding UTF8 -Path $env:GITHUB_OUTPUT -Value "envName=$envName" - - - name: Read secrets - id: ReadSecrets - uses: microsoft/AL-Go/Actions/ReadSecrets@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: ${{ matrix.shell }} - gitHubSecrets: ${{ toJson(secrets) }} - getSecrets: '${{ steps.envName.outputs.envName }}-AuthContext,${{ steps.envName.outputs.envName }}_AuthContext,AuthContext' - - - name: Deploy to Business Central - id: Deploy - uses: microsoft/AL-Go/Actions/Deploy@91b96c2b294be6f823277dafe6f03350abfb9d23 - env: - Secrets: '${{ steps.ReadSecrets.outputs.Secrets }}' - with: - shell: ${{ matrix.shell }} - environmentName: ${{ matrix.environment }} - artifactsFolder: '.artifacts' - type: 'CD' - deploymentEnvironmentsJson: ${{ needs.Initialization.outputs.deploymentEnvironmentsJson }} - - - name: Deploy to Power Platform - if: env.type == 'PTE' && env.powerPlatformSolutionFolder != '' - uses: microsoft/AL-Go/Actions/DeployPowerPlatform@91b96c2b294be6f823277dafe6f03350abfb9d23 - env: - Secrets: '${{ steps.ReadSecrets.outputs.Secrets }}' - with: - shell: powershell - environmentName: ${{ matrix.environment }} - artifactsFolder: '.artifacts' - deploymentEnvironmentsJson: ${{ needs.Initialization.outputs.deploymentEnvironmentsJson }} - - Deliver: - needs: [ Initialization, Build1, Build ] - if: (!cancelled()) && (needs.Build1.result == 'success' || needs.Build1.result == 'skipped') && (needs.Build.result == 'success' || needs.Build.result == 'skipped') && needs.Initialization.outputs.deliveryTargetsJson != '[]' - strategy: - matrix: - deliveryTarget: ${{ fromJson(needs.Initialization.outputs.deliveryTargetsJson) }} - fail-fast: false - runs-on: [ windows-latest ] - name: Deliver to ${{ matrix.deliveryTarget }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Download artifacts - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - env: - ACTIONS_RUNNER_DISABLE_NODE_MAGLEV: 1 - with: - path: '.artifacts' - - - name: Read settings - uses: microsoft/AL-Go/Actions/ReadSettings@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - - - name: Read secrets - id: ReadSecrets - uses: microsoft/AL-Go/Actions/ReadSecrets@91b96c2b294be6f823277dafe6f03350abfb9d23 - with: - shell: powershell - gitHubSecrets: ${{ toJson(secrets) }} - getSecrets: '${{ matrix.deliveryTarget }}Context' - - - name: Deliver - uses: microsoft/AL-Go/Actions/Deliver@91b96c2b294be6f823277dafe6f03350abfb9d23 - env: - Secrets: '${{ steps.ReadSecrets.outputs.Secrets }}' - with: - shell: powershell - type: 'CD' - projects: ${{ needs.Initialization.outputs.projects }} - deliveryTarget: ${{ matrix.deliveryTarget }} - artifacts: '.artifacts' + Batch03: + needs: [Plan, Batch02] + if: always() && !cancelled() && needs.Plan.result == 'success' + uses: ./.github/workflows/SqlApiComparisonBatch.yaml + secrets: inherit + with: + matrix: ${{ needs.Plan.outputs.batch03 }} + authorization: ${{ inputs.authorization }} - PostProcess: - needs: [ Initialization, Build1, Build, Deploy, Deliver, DeployALDoc, CodeAnalysisUpload ] - if: (!cancelled()) - runs-on: [ windows-latest ] - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + Batch04: + needs: [Plan, Batch03] + if: always() && !cancelled() && needs.Plan.result == 'success' + uses: ./.github/workflows/SqlApiComparisonBatch.yaml + secrets: inherit + with: + matrix: ${{ needs.Plan.outputs.batch04 }} + authorization: ${{ inputs.authorization }} - - name: Finalize the workflow - id: PostProcess - uses: microsoft/AL-Go/Actions/WorkflowPostProcess@91b96c2b294be6f823277dafe6f03350abfb9d23 - env: - GITHUB_TOKEN: ${{ github.token }} - with: - shell: powershell - telemetryScopeJson: ${{ needs.Initialization.outputs.telemetryScopeJson }} - currentJobContext: ${{ toJson(job) }} + Batch05: + needs: [Plan, Batch04] + if: always() && !cancelled() && needs.Plan.result == 'success' + uses: ./.github/workflows/SqlApiComparisonBatch.yaml + secrets: inherit + with: + matrix: ${{ needs.Plan.outputs.batch05 }} + authorization: ${{ inputs.authorization }} diff --git a/.github/workflows/PullRequestHandler.yaml b/.github/workflows/PullRequestHandler.yaml index 5bf5c05d665..e7875411767 100644 --- a/.github/workflows/PullRequestHandler.yaml +++ b/.github/workflows/PullRequestHandler.yaml @@ -35,7 +35,7 @@ jobs: Initialization: needs: [ PregateCheck ] - if: (!failure() && !cancelled()) + if: (!failure() && !cancelled()) && github.head_ref != 'features/646383-sql-api-warmup-experiment' && github.head_ref != 'features/646383-sql-api-two-arm-experiment' && github.head_ref != 'features/646383-sql-api-300-trial-comparison' && github.head_ref != 'features/653457-sql-platform-fix-uptake' runs-on: [ windows-latest ] outputs: projects: ${{ steps.determineProjectsToBuild.outputs.ProjectsJson }} @@ -93,7 +93,7 @@ jobs: Build1: needs: [ Initialization, CustomJob-VerifyAppChanges ] - if: (!failure()) && (!cancelled()) && fromJson(needs.Initialization.outputs.buildOrderJson)[0].projectsCount > 0 + if: (!failure()) && (!cancelled()) && needs.Initialization.result == 'success' && fromJson(needs.Initialization.outputs.buildOrderJson)[0].projectsCount > 0 strategy: matrix: include: ${{ fromJson(needs.Initialization.outputs.buildOrderJson)[0].buildDimensions }} @@ -119,7 +119,7 @@ jobs: Build: needs: [ Initialization, Build1, CustomJob-VerifyAppChanges ] - if: (!failure()) && (!cancelled()) && (needs.Build1.result == 'success' || needs.Build1.result == 'skipped') && fromJson(needs.Initialization.outputs.buildOrderJson)[1].projectsCount > 0 + if: (!failure()) && (!cancelled()) && needs.Initialization.result == 'success' && (needs.Build1.result == 'success' || needs.Build1.result == 'skipped') && fromJson(needs.Initialization.outputs.buildOrderJson)[1].projectsCount > 0 strategy: matrix: include: ${{ fromJson(needs.Initialization.outputs.buildOrderJson)[1].buildDimensions }} diff --git a/.github/workflows/SqlApiComparisonBatch.yaml b/.github/workflows/SqlApiComparisonBatch.yaml new file mode 100644 index 00000000000..3b4930a2a8b --- /dev/null +++ b/.github/workflows/SqlApiComparisonBatch.yaml @@ -0,0 +1,117 @@ +name: 'SQL platform uptake pair - DO NOT MERGE' + +on: + workflow_call: + inputs: + matrix: + required: true + type: string + authorization: + required: true + type: string + +permissions: + actions: read + contents: read + id-token: write + packages: read + +jobs: + Pilot: + name: Trial ${{ matrix.experiment }}/${{ matrix.country }}/${{ matrix.trial }} + if: github.repository == 'microsoft/BCApps' && github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/features/653457-sql-platform-fix-uptake' && github.run_attempt == 1 && inputs.authorization == 'AB653457-fixed-platform-original-control-10' + strategy: + fail-fast: false + max-parallel: 2 + matrix: ${{ fromJSON(inputs.matrix) }} + runs-on: GitHub-BCAppsPL + timeout-minutes: 120 + defaults: + run: + shell: pwsh + env: + ALGoOrgSettings: ${{ vars.ALGoOrgSettings }} + ALGoRepoSettings: ${{ vars.ALGoRepoSettings }} + BC_SQL_PILOT_ARM: control + BC_SQL_API_EXPERIMENT: ${{ matrix.experiment }} + BC_SQL_PILOT_COUNTRY: ${{ matrix.country }} + BC_SQL_PILOT_TRIAL: ${{ matrix.trial }} + BC_SQL_UPTAKE_AUTHORIZATION: ${{ inputs.authorization }} + BuildMode: IntegrationTests + steps: + - name: Checkout experiment + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + with: + lfs: true + fetch-depth: 0 + + - name: Verify baseline PowerShell 7 host + run: | + if ($PSVersionTable.PSEdition -ne 'Core' -or $PSVersionTable.PSVersion.Major -ne 7) { + throw 'The pinned baseline executes on PowerShell 7; this pilot must use the same shell.' + } + $output = Join-Path $env:GITHUB_WORKSPACE 'sql-reset-pilot-output' + New-Item -ItemType Directory $output -Force | Out-Null + @{ + edition = $PSVersionTable.PSEdition + version = $PSVersionTable.PSVersion.ToString() + executable = (Get-Process -Id $PID).Path + utc = [DateTime]::UtcNow.ToString('o') + } | ConvertTo-Json | Tee-Object -FilePath (Join-Path $output 'shell-preflight.json') + + - name: Validate provenance and download exact compiled PR2 packages + id: packages + env: + GH_TOKEN: ${{ github.token }} + run: | + & .\build\scripts\SqlResetPilot\Prepare.ps1 + + - name: Read pinned country Integration settings + uses: microsoft/AL-Go/Actions/ReadSettings@91b96c2b294be6f823277dafe6f03350abfb9d23 + with: + shell: pwsh + project: build/projects/Test Apps ${{ matrix.country }} Uptake${{ matrix.trial }}${{ matrix.experiment }} + buildMode: IntegrationTests + + - name: Read normal disposable CI license and package secrets + id: secrets + uses: microsoft/AL-Go/Actions/ReadSecrets@91b96c2b294be6f823277dafe6f03350abfb9d23 + with: + shell: pwsh + gitHubSecrets: ${{ toJson(secrets) }} + getSecrets: 'licenseFileUrl,gitHubPackagesContext,applicationInsightsConnectionString,appDependencySecrets' + + - name: Execute original pipeline with bounded clean-test prefix + uses: microsoft/AL-Go/Actions/RunPipeline@91b96c2b294be6f823277dafe6f03350abfb9d23 + env: + Secrets: '${{ steps.secrets.outputs.Secrets }}' + with: + shell: pwsh + project: build/projects/Test Apps ${{ matrix.country }} Uptake${{ matrix.trial }}${{ matrix.experiment }} + buildMode: IntegrationTests + artifact: ${{ steps.packages.outputs.artifact }} + installAppsJson: ${{ steps.packages.outputs.apps }} + installTestAppsJson: ${{ steps.packages.outputs.tests }} + + - name: Export diagnostics and tear down only owned disposable container + if: always() + run: | + & .\build\scripts\SqlResetPilot\Finalize.ps1 + + - name: Preserve raw outcomes (including failures) + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: sql-platform-uptake-${{ matrix.experiment }}-${{ matrix.country }}-${{ matrix.trial }}-${{ github.run_id }} + retention-days: 14 + include-hidden-files: true + if-no-files-found: error + path: | + sql-reset-pilot-output/** + build/projects/Test Apps ${{ matrix.country }} Uptake${{ matrix.trial }}${{ matrix.experiment }}/TestResults*.xml + build/projects/Test Apps ${{ matrix.country }} Uptake${{ matrix.trial }}${{ matrix.experiment }}/ContainerEventLog.evtx + build/projects/Test Apps ${{ matrix.country }} Uptake${{ matrix.trial }}${{ matrix.experiment }}/BuildOutput.txt + build/projects/Test Apps ${{ matrix.country }} Uptake${{ matrix.trial }}${{ matrix.experiment }}/.buildartifacts/**/*.xml + build/projects/Test Apps ${{ matrix.country }} Uptake${{ matrix.trial }}${{ matrix.experiment }}/.buildartifacts/**/*.log + build/projects/Test Apps ${{ matrix.country }} Uptake${{ matrix.trial }}${{ matrix.experiment }}/.buildartifacts/**/*.evtx + build/projects/Test Apps ${{ matrix.country }} Uptake${{ matrix.trial }}${{ matrix.experiment }}/.buildartifacts/**/BuildOutput.txt diff --git a/build/Packages.json b/build/Packages.json index 3afa71226b9..2ec65533b0a 100644 --- a/build/Packages.json +++ b/build/Packages.json @@ -9,7 +9,7 @@ "_comment": "Used to fetch app baselines from BC artifacts" }, "BCPlatform": { - "Version": "30.0.55665.0", + "Version": "30.0.56092.0", "Source": "BCPlatform", "_comment": "The BC platform version, fetched from the platform CDN" } diff --git a/build/scripts/NewBcContainer.ps1 b/build/scripts/NewBcContainer.ps1 index 78871ab947b..c5b82654c7c 100644 --- a/build/scripts/NewBcContainer.ps1 +++ b/build/scripts/NewBcContainer.ps1 @@ -22,7 +22,28 @@ if ($platformVersion) { $parameters.platformArtifactUrl = "$platformUrl/platform" } +if ($env:BC_SQL_PILOT_ARM) { + & (Join-Path $PSScriptRoot 'SqlResetPilot\ContainerPreflight.ps1') -Parameters $parameters +} New-BcContainer @parameters +if ($env:BC_SQL_PILOT_ARM) { + $runtime = Invoke-ScriptInBcContainer -containerName $parameters.ContainerName -scriptblock { + $commands = @('Get-NAVTenant', 'Dismount-NAVTenant', 'Mount-NAVTenant', 'Test-NAVDatabase', 'Copy-NAVDatabase', 'Remove-NAVDatabase') + @{ + commands = @($commands | ForEach-Object { + $command = Get-Command $_ -ErrorAction Stop + @{ name = $command.Name; version = [string]$command.Version; parameters = @($command.Parameters.Keys) } + }) + nst = @(Get-Process 'Microsoft.Dynamics.Nav.Server' | ForEach-Object { + @{ pid = $_.Id; version = $_.FileVersion } + }) + } + } + $runtime | ConvertTo-Json -Depth 6 | Set-Content (Join-Path $env:BC_SQL_PILOT_OUTPUT 'runtime-preflight.json') + if (@($runtime.nst).Count -ne 1 -or $runtime.nst[0].version -notmatch '^30\.0\.56092\.0(?:\s|$)') { + throw 'Installed NST is not the predeclared 30.0.56092.0 runtime.' + } +} if ($parameters.auth -in @('UserPassword', 'NavUserPassword')) { if (-not $parameters.credential) { diff --git a/build/scripts/ParallelTestExecution.psm1 b/build/scripts/ParallelTestExecution.psm1 index f8ed562ccee..f19ad9deb82 100644 --- a/build/scripts/ParallelTestExecution.psm1 +++ b/build/scripts/ParallelTestExecution.psm1 @@ -13,6 +13,10 @@ if (-not (Get-Command Write-Log -ErrorAction SilentlyContinue)) { } } Import-Module (Join-Path $PSScriptRoot "ALAppBuild.psm1" -Resolve) +Import-Module (Join-Path $PSScriptRoot 'SqlApiTestRetry.psm1' -Resolve) +if ($env:BC_SQL_PILOT_ARM) { + Import-Module (Join-Path $PSScriptRoot 'SqlResetPilot\Lifecycle.psm1') +} <# .SYNOPSIS @@ -47,6 +51,35 @@ function Get-DisabledTestsForApp { return @($disabledTests) } +function Test-SqlApiExperiment { + if ($env:GITHUB_REF -eq 'refs/heads/features/653457-sql-platform-fix-uptake') { + return ($env:GITHUB_REPOSITORY -eq 'microsoft/BCApps' -and + $env:GITHUB_EVENT_NAME -eq 'workflow_dispatch' -and $env:GITHUB_RUN_ATTEMPT -eq '1' -and + $env:BC_SQL_UPTAKE_AUTHORIZATION -eq 'AB653457-fixed-platform-original-control-10' -and + $env:BC_SQL_PILOT_ARM -eq 'control' -and $env:BC_SQL_API_EXPERIMENT -eq 'control') + } + return ($env:GITHUB_REPOSITORY -eq 'microsoft/BCApps' -and + $env:GITHUB_REF -eq 'refs/heads/features/646383-sql-api-300-trial-comparison' -and + $env:GITHUB_EVENT_NAME -eq 'workflow_dispatch' -and $env:GITHUB_RUN_ATTEMPT -eq '1' -and + $env:BC_SQL_PILOT_ARM -eq 'control' -and $env:BC_SQL_API_EXPERIMENT -in @('control', 'warmup', 'retry')) +} + +function Test-SqlApiWarmupEnabled { + if ($env:GITHUB_REF -eq 'refs/heads/features/653457-sql-platform-fix-uptake') { + if (-not (Test-SqlApiExperiment)) { throw 'Invalid control-only uptake context; refusing warmup fallback.' } + return $false + } + return ($env:BC_SQL_PILOT_ARM -and + (-not (Test-SqlApiExperiment) -or $env:BC_SQL_API_EXPERIMENT -ne 'control')) +} + +function Get-TestJobResultFileName { + param([string]$Path, [string]$Suffix) + $dir = [System.IO.Path]::GetDirectoryName($Path) + if (-not $dir) { $dir = '.' } + Join-Path $dir "$([System.IO.Path]::GetFileNameWithoutExtension($Path))-$Suffix$([System.IO.Path]::GetExtension($Path))" +} + function Get-ParametersForCommand { param( [Parameter(Mandatory=$true)] @@ -376,9 +409,12 @@ function New-BcTestTenantTemplate { [string]$SourceDatabaseName ) - $result = @(Invoke-ScriptInBcContainer -containerName $ContainerName -useSession $false -scriptblock { Param($sourceDatabaseName) + $result = @(Invoke-ScriptInBcContainer -containerName $ContainerName -useSession $false -scriptblock { Param($sourceDatabaseName, $sqlPilot) $templateDatabaseName = "$sourceDatabaseName-test-template" - $maxAttempts = 3 + if ($sqlPilot -and (Test-NAVDatabase -DatabaseName $templateDatabaseName)) { + throw 'Pilot template already exists; it must never be overwritten.' + } + $maxAttempts = if ($sqlPilot) { 1 } else { 3 } $retryDelaySeconds = 5 for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) { try { @@ -398,7 +434,7 @@ function New-BcTestTenantTemplate { } } $templateDatabaseName - } -argumentList $SourceDatabaseName) + } -argumentList $SourceDatabaseName, ([bool]$env:BC_SQL_PILOT_ARM)) if ($result.Count -eq 0) { throw "Creating the clean test tenant template returned no database name." @@ -430,6 +466,12 @@ function Reset-BcTestTenant { [string]$TemplateDatabaseName ) + if ($env:BC_SQL_PILOT_ARM) { + Invoke-SqlPilotReset -ContainerName $ContainerName -Tenant $Tenant -DatabaseName $TenantDatabaseName ` + -TemplateDatabaseName $TemplateDatabaseName + return + } + Invoke-ScriptInBcContainer -containerName $ContainerName -useSession $false -scriptblock { Param($tenant, $tenantDatabaseName, $templateDatabaseName) @@ -634,14 +676,61 @@ function Receive-TestJobResult { $output = $sb.ToString() $outcome = 'Passed' + $sqlRetryEvidence = $null if ($Job.State -eq 'Failed' -or $Job.State -eq 'Stopped') { - if ((Test-TransientTestFailure $output) -and -not $Retried.ContainsKey($Entry.appName)) { + if (-not $env:BC_SQL_PILOT_ARM -and (Test-TransientTestFailure $output) -and -not $Retried.ContainsKey($Entry.appName)) { $outcome = 'Transient' } else { $outcome = 'Failed' + if ($Job.State -eq 'Failed' -and -not $Retried.ContainsKey($Entry.appName) -and + $Entry.PSObject.Properties['SqlRetryContext'] -and $Entry.SqlRetryContext -and + (Test-SqlApiExperiment)) { + $sqlRetryEvidence = Get-SqlApiTestRetryEvidence -Context $Entry.SqlRetryContext + if ($sqlRetryEvidence -and $env:BC_SQL_API_EXPERIMENT -eq 'retry') { $outcome = 'SqlPoolRetry' } + } } } + if ($Entry.PSObject.Properties['SqlRetryContext'] -and $Entry.SqlRetryContext) { + $context = $Entry.SqlRetryContext + if (-not (Test-SqlApiExperimentSelection -Context $context -Experiment $env:BC_SQL_API_EXPERIMENT)) { + $outcome = 'Failed' + $sqlRetryEvidence = $null + } + if ($Entry.SqlRetryExpectedTests.Count -gt 0 -and $outcome -eq 'Passed') { + if (-not (Test-SqlApiRetryResult -Context $context -ExpectedTests $Entry.SqlRetryExpectedTests)) { + $outcome = 'Failed' + } + } + $attemptDirectory = Join-Path $env:BC_SQL_PILOT_OUTPUT "test-attempts\$($context.Tenant)-$($context.CodeunitId)-$($context.Attempt)" + New-Item -ItemType Directory -Path $attemptDirectory -Force -ErrorAction Stop | Out-Null + foreach ($key in $context.ResultFiles.Keys) { + $path = $context.ResultFiles[$key] + if (Test-Path -LiteralPath $path) { + Copy-Item -LiteralPath $path -Destination (Join-Path $attemptDirectory $key) -ErrorAction Stop + } + } + @{ + codeunitId = $context.CodeunitId; tenant = $context.Tenant; attempt = $context.Attempt + outcome = $outcome; jobState = [string]$Job.State; startedUtc = $context.StartedUtc.ToString('o') + completedUtc = [datetime]::UtcNow.ToString('o'); experiment = $env:BC_SQL_API_EXPERIMENT + sqlPoolFailureConfirmed = [bool]$sqlRetryEvidence + retryEligible = ($outcome -eq 'SqlPoolRetry'); expectedCases = $context.TestCount + } | ConvertTo-Json | Set-Content (Join-Path $attemptDirectory 'outcome.json') -ErrorAction Stop + if ($context.Attempt -eq 2 -and $outcome -eq 'Passed') { + foreach ($key in $context.ResultFiles.Keys) { + $first = Join-Path $env:BC_SQL_PILOT_OUTPUT "test-attempts\$($context.Tenant)-$($context.CodeunitId)-1\$key" + if (-not (Test-Path $first) -or -not (Test-Path $context.ResultFiles[$key])) { + throw 'Cannot merge retry without both original and retry result files.' + } + Merge-TestResultFiles -targetFile $context.FinalResultFiles[$key] ` + -sourceFiles @($first, $context.ResultFiles[$key]) + } + } + } + if ($env:BC_SQL_PILOT_ARM) { + $output | Set-Content (Join-Path $env:BC_SQL_PILOT_OUTPUT "worker-$($Job.Id).log") -Encoding UTF8 + } Remove-Job -Job $Job -Force return [PSCustomObject]@{ @@ -649,6 +738,7 @@ function Receive-TestJobResult { AppName = $Entry.appName Tenant = $Entry.tenant JobState = $Job.State + SqlRetryEvidence = $sqlRetryEvidence } } @@ -740,13 +830,44 @@ function Start-RequiredDisabledDispatch { } } + $sqlRetryContext = $null + $sqlRetryExpectedTests = @() + $fileSuffix = $TenantInfo.Id + if (Test-SqlApiExperiment) { + if (-not $Parameters.JUnitResultFileName) { throw 'Comparison requires JUnit evidence.' } + $attempt = 1 + $finalFiles = @{} + if ($State.sqlRetryEvidence.ContainsKey($WorkItem.Key)) { + $attempt = 2 + $fileSuffix = "$($TenantInfo.Id)-sqlretry-$($WorkItem.CodeunitId)" + $sqlRetryExpectedTests = @($State.sqlRetryEvidence[$WorkItem.Key].TestCases) + # BCH ReRun selects only failing methods. This experiment retries the entire codeunit. + $codeunitParameters.Remove('ReRun') | Out-Null + } + $files = @{} + foreach ($key in $appendKeys.Keys) { + if ($Parameters.ContainsKey($key) -and $Parameters[$key]) { + $files[$key] = Get-TestJobResultFileName $Parameters[$key] $fileSuffix + $finalFiles[$key] = Get-TestJobResultFileName $Parameters[$key] $TenantInfo.Id + if ($attempt -eq 2 -and (Test-Path $files[$key])) { throw 'Retry result file already exists.' } + } + } + $sqlRetryContext = [PSCustomObject]@{ + ContainerName = $Parameters.containerName; Tenant = $TenantInfo.Id + CodeunitId = $WorkItem.CodeunitId; TestCount = $WorkItem.TestCount + StartedUtc = [datetime]::UtcNow; ResultFiles = $files; FinalResultFiles = $finalFiles + Attempt = $attempt; OutputDirectory = $env:BC_SQL_PILOT_OUTPUT + } + } $job = Start-TestJob -parameters $codeunitParameters -tenant $TenantInfo.Id -scriptPath $ScriptPath ` - -testType $TestType -skipAutomaticDisabledPass + -testType $TestType -skipAutomaticDisabledPass -fileSuffix $fileSuffix $State.jobs = @($State.jobs) + @( [PSCustomObject]@{ jobId = $job.Id tenant = $TenantInfo.Id appName = $WorkItem.Key + SqlRetryContext = $sqlRetryContext + SqlRetryExpectedTests = $sqlRetryExpectedTests } ) Start-Sleep -Seconds 1 @@ -783,6 +904,7 @@ function Invoke-RequiredDisabledTestExecution { transient = @() retried = @{} retryTenant = @{} + sqlRetryEvidence = @{} } $pending = @($WorkItems) @@ -830,12 +952,22 @@ function Invoke-RequiredDisabledTestExecution { Reset-BcTestTenant -ContainerName $Parameters.containerName -Tenant $dispatch.TenantInfo.Id ` -TenantDatabaseName $dispatch.TenantInfo.DatabaseName -TemplateDatabaseName $TemplateDatabaseName } + if (Test-SqlApiWarmupEnabled) { + foreach ($dispatch in $batch) { + Invoke-SqlPilotCompaniesProbe -ContainerName $Parameters.containerName -Tenant $dispatch.TenantInfo.Id ` + -Credential $Parameters.credential -CompanyName $Parameters.companyName + } + } foreach ($dispatch in $batch) { Start-RequiredDisabledDispatch -Parameters $Parameters -WorkItem $dispatch.WorkItem ` -TenantInfo $dispatch.TenantInfo ` -ScriptPath $ScriptPath -TestType $TestType -State $state -Verb $dispatch.Verb } $null = Wait-ForAllTestJobs -state $state + if ($env:BC_SQL_PILOT_ARM -and $state.hasFailures) { + $state.hasFailures = $true + break + } } return (-not $state.hasFailures) @@ -860,6 +992,20 @@ function Register-TestJobOutcome { $State ) + if ($Result.Outcome -eq 'SqlPoolRetry') { + if (-not (Test-SqlApiExperiment) -or $env:BC_SQL_API_EXPERIMENT -ne 'retry' -or + -not $Result.SqlRetryEvidence -or $State.retried.ContainsKey($Result.AppName)) { + $State.hasFailures = $true + return + } + $State.sqlRetryEvidence[$Result.AppName] = $Result.SqlRetryEvidence + $State.transient = @($State.transient) + @([PSCustomObject]@{ Key = $Result.AppName; Tenant = $Result.Tenant }) + return + } + if ($env:BC_SQL_PILOT_ARM -and $Result.Outcome -in @('Failed', 'Transient')) { + $State.hasFailures = $true + return + } switch ($Result.Outcome) { 'Transient' { Write-Host "Transient platform race for '$($Result.AppName)' on '$($Result.Tenant)'. Queued for one retry." @@ -1075,6 +1221,9 @@ function Wait-ForAllTestJobs { $result = Receive-TestJobResult -Entry $entry -Job $pendingJob -Retried $state.retried Register-TestJobOutcome -Result $result -State $state + } elseif (Test-SqlApiExperiment) { + $state.hasFailures = $true + Write-Host "::warning::Expected experiment worker job $($entry.jobId) is missing; failing closed." } } # All jobs in $state.jobs have been received and removed; clear the list so any later @@ -1236,6 +1385,46 @@ function Invoke-WarmupDispatch { return @($Pending | Select-Object -Skip 1) } +function Invoke-SqlPilotWarmup { + param( + [hashtable]$Parameters, [string[]]$AppNames, [hashtable]$AppIdByName, + [string[]]$Tenants, [string]$ScriptPath, [string]$TestType, [string[]]$CleanTenantAppNames + ) + if ($Parameters.tenant -ne 'default' -or $Tenants[0] -ne 'default' -or + $AppNames.Count -le 1 -or -not $AppIdByName[$AppNames[0]]) { + throw 'Original first-app warmup cannot be guaranteed on the default tenant.' + } + $warmupDirectory = Join-Path $env:BC_SQL_PILOT_OUTPUT 'warmup' + New-Item -ItemType Directory $warmupDirectory -Force | Out-Null + $warmupParameters = $Parameters.Clone() + foreach ($key in @('XUnitResultFileName', 'JUnitResultFileName')) { + if ($warmupParameters[$key]) { + $warmupParameters[$key] = Join-Path $warmupDirectory ([IO.Path]::GetFileName($warmupParameters[$key])) + } + } + $warmupState = [PSCustomObject]@{ + jobs = @(); hasFailures = $false; transient = @(); retried = @{}; retryTenant = @{} + rerun = @(); rerunDone = @{}; rerunBudget = 0; tenantCount = $Tenants.Count + } + $observation = @{ + phase = 'warmup'; app = $AppNames[0]; tenant = 'default' + startedUtc = [DateTime]::UtcNow.ToString('o'); passed = $false; retries = 0 + } + try { + $remaining = @(Invoke-WarmupDispatch -Parameters $warmupParameters -Pending $AppNames -AppIdByName $AppIdByName ` + -Tenants $Tenants -ScriptPath $ScriptPath -TestType $TestType -State $warmupState ` + -CleanTenantAppNames $CleanTenantAppNames) + if ($remaining.Count -ne ($AppNames.Count - 1) -or $warmupState.hasFailures -or + $warmupState.transient.Count -gt 0 -or $warmupState.rerun.Count -gt 0 -or $warmupState.jobs.Count -gt 0) { + throw 'First-app warmup failed or did not complete; no retry or clean-lane dispatch is permitted.' + } + $observation.passed = $true + } finally { + $observation.completedUtc = [DateTime]::UtcNow.ToString('o') + $observation | ConvertTo-Json | Set-Content (Join-Path $warmupDirectory 'outcome.json') -Encoding UTF8 + } +} + <# .SYNOPSIS Deletes the result file written by a rerun, so it cannot take part in the merge. @@ -1327,6 +1516,10 @@ function Invoke-ParallelTestExecution { } $tenantInfo = @(Get-AvailableBcTenantInfo -containerName $parameters.containerName) + if ($env:BC_SQL_PILOT_ARM) { + Initialize-SqlResetPilot -ContainerName $parameters.containerName -TenantInfo $tenantInfo ` + -Arm $env:BC_SQL_PILOT_ARM -RunId $env:GITHUB_RUN_ID -OutputDirectory $env:BC_SQL_PILOT_OUTPUT + } $tenants = @($tenantInfo | ForEach-Object { $_.Id }) Write-Host "Available tenants: $($tenants -join ', ')" @@ -1384,6 +1577,11 @@ function Invoke-ParallelTestExecution { -AppNamesToTest $appNamesToTest -AppIdByName $appIdByName ) } + if ($env:BC_SQL_PILOT_ARM) { + $requiredDisabledWorkItems = @(Select-SqlPilotPrefix -WorkItems $requiredDisabledWorkItems) + $requiredDisabledWorkItems | ConvertTo-Json -Depth 5 | + Set-Content (Join-Path $env:BC_SQL_PILOT_OUTPUT 'ordered-prefix.json') -Encoding UTF8 + } $templateDatabaseName = "" try { if ($requiredDisabledWorkItems.Count -gt 0) { @@ -1407,6 +1605,12 @@ function Invoke-ParallelTestExecution { } $state | ConvertTo-Json -Depth 5 | Set-Content $stateFile -Force + if (Test-SqlApiWarmupEnabled) { + if (-not $templateDatabaseName) { throw 'Pristine template must be frozen before warmup.' } + Invoke-SqlPilotWarmup -Parameters $parameters -AppNames $appNamesToTest -AppIdByName $appIdByName ` + -Tenants $tenants -ScriptPath $scriptPath -TestType $testType -CleanTenantAppNames $cleanTenantAppNames + } + if ($requiredDisabledWorkItems.Count -gt 0) { try { $requiredDisabledPassed = Invoke-RequiredDisabledTestExecution -Parameters $parameters ` @@ -1417,13 +1621,52 @@ function Invoke-ParallelTestExecution { } } finally { - foreach ($cleanTenant in $cleanTenantInfo) { + foreach ($cleanTenant in @($cleanTenantInfo | Where-Object { -not $env:BC_SQL_PILOT_ARM })) { Reset-BcTestTenant -ContainerName $parameters.containerName -Tenant $cleanTenant.Id ` -TenantDatabaseName $cleanTenant.DatabaseName -TemplateDatabaseName $templateDatabaseName } } } + if ($env:BC_SQL_PILOT_ARM) { + Merge-TenantTestResults -parameters $parameters -tenants $tenants -workItems $requiredDisabledWorkItems -rerunSuffixes @() + if ((Test-SqlApiExperiment) -and (Test-Path $parameters.JUnitResultFileName)) { + [xml]$finalXml = Get-Content $parameters.JUnitResultFileName -Raw + $finalCases = @($finalXml.SelectNodes('/testsuites/testsuite/testcase')) + $skippedCount = @($finalCases | Where-Object { $_.SelectSingleNode('skipped') }).Count + $completeCohort = $finalCases.Count -eq 253 -and $skippedCount -eq 19 -and + $finalXml.SelectNodes('/testsuites/testsuite').Count -eq 21 + $failedCount = @($finalCases | Where-Object { + $_.SelectSingleNode('failure | error') -or $_.GetAttribute('result') -eq 'Fail' + }).Count + if (-not $completeCohort -or $failedCount -gt 0) { $state.hasFailures = $true } + $attempts = @(Get-ChildItem (Join-Path $env:BC_SQL_PILOT_OUTPUT 'test-attempts') -Filter outcome.json -Recurse -File | + ForEach-Object { Get-Content $_.FullName -Raw | ConvertFrom-Json }) + @{ + total = $finalCases.Count + failed = $failedCount + skipped = $skippedCount + passed = @($finalCases | Where-Object { -not $_.SelectSingleNode('failure | error | skipped') }).Count + suites = $finalXml.SelectNodes('/testsuites/testsuite').Count + experiment = $env:BC_SQL_API_EXPERIMENT + completeCohort = $completeCohort + firstAttemptSqlFailures = @($attempts | Where-Object { $_.attempt -eq 1 -and $_.sqlPoolFailureConfirmed }).Count + firstAttemptFailedCodeunits = @($attempts | Where-Object { $_.attempt -eq 1 -and $_.outcome -ne 'Passed' }).Count + retryRecoveries = @($attempts | Where-Object { $_.attempt -eq 2 -and $_.outcome -eq 'Passed' }).Count + failedRetries = @($attempts | Where-Object { $_.attempt -eq 2 -and $_.outcome -ne 'Passed' }).Count + firstAttemptsAndRetries = 'See test-attempts; final XML replaces only validated recovered CUs.' + } | ConvertTo-Json | Set-Content (Join-Path $env:BC_SQL_PILOT_OUTPUT 'final-counts.json') + } elseif (Test-SqlApiExperiment) { + $state.hasFailures = $true + } + $state.finalResult = -not $state.hasFailures + $state.completed = $true + $state | ConvertTo-Json -Depth 5 | Set-Content $stateFile -Force + @{ completedUtc = [DateTime]::UtcNow.ToString('o'); passed = $state.finalResult; selectedCodeunits = $requiredDisabledWorkItems.Count } | + ConvertTo-Json | Set-Content (Join-Path $env:BC_SQL_PILOT_OUTPUT 'outcome.json') -Encoding UTF8 + return $state.finalResult + } + # Single dispatch loop, FIFO. TestConfiguration.json lists the smallest app first (a cheap # serial warmup) and the rest longest-first (LPT, keeps the tail short). The retry cap lives in # Receive-TestJobResult: an app already in $state.retried is classified as Failed on a re-fail. @@ -1521,7 +1764,7 @@ function Invoke-ParallelTestExecution { return $allPassed } finally { - if ($templateDatabaseName) { + if ($templateDatabaseName -and -not $env:BC_SQL_PILOT_ARM) { Remove-BcTestTenantTemplate -ContainerName $parameters.containerName ` -TemplateDatabaseName $templateDatabaseName } diff --git a/build/scripts/SqlApiTestRetry.psm1 b/build/scripts/SqlApiTestRetry.psm1 new file mode 100644 index 00000000000..76e1a2614c6 --- /dev/null +++ b/build/scripts/SqlApiTestRetry.psm1 @@ -0,0 +1,202 @@ +<# +.SYNOPSIS + Correlates clean-codeunit HTTP failures with NST SQL-pool exceptions. +.DESCRIPTION + This is a manual diagnostic experiment, not a generic HTTP retry or a pool-lifecycle fix. + Every failed case must have a request CorrelationId matching an NST ClientSessionId, + a NullReferenceException in AcquireSqlConnectionFromPool, and the observed OData + metadata stack, within this dispatch's time window. Missing evidence fails closed. + The scheduler permits only one retry, restores the tenant first, and reruns the entire + codeunit. Original results and matching events are retained separately from final results. + The scheduler enables retry only on the exact manual comparison branch, retry arm, attempt one. + All arms classify and preserve matching first-attempt evidence without authorizing other retries. + SqlApiRetryEvidence JSON files under the diagnostic output are uploaded with raw outcomes, + including on successful runs, so recovered failures remain visible without duplicating cases. +#> +function Get-SqlApiRetrySuite { + param($Context) + + [xml]$document = Get-Content -LiteralPath $Context.ResultFiles.JUnitResultFileName -Raw -ErrorAction Stop + $suites = @($document.SelectNodes('/testsuites/testsuite') | Where-Object { + ($_.GetAttribute('name') -split ' ', 2)[0] -eq [string]$Context.CodeunitId + }) + if ($suites.Count -ne 1) { + throw "Expected exactly one JUnit suite for codeunit $($Context.CodeunitId), found $($suites.Count)." + } + return ,$suites[0] +} + +function Get-SqlApiRetryEvents { + param( + [string]$ContainerName, + [datetime]$StartedUtc, + [datetime]$FinishedUtc + ) + + return @(Invoke-ScriptInBcContainer -containerName $ContainerName -scriptblock { + param($start, $end) + try { + $events = @(Get-WinEvent -FilterHashtable @{ + LogName = 'Application' + ProviderName = 'MicrosoftDynamicsNavServer*' + Id = 701 + StartTime = [datetime]::Parse($start).ToUniversalTime() + EndTime = [datetime]::Parse($end).ToUniversalTime() + } -MaxEvents 1000 -ErrorAction Stop) + } catch { + if ($_.FullyQualifiedErrorId -like 'NoMatchingEventsFound*') { + return + } + throw + } + foreach ($eventRecord in $events) { + $eventRecord.ToXml() + } + } -argumentList $StartedUtc.ToString('o'), $FinishedUtc.ToString('o')) +} + +<# +.SYNOPSIS + Persists original JUnit and correlated NST events before authorizing one clean-codeunit retry. +#> +function Get-SqlApiTestRetryEvidence { + param($Context) + + try { + $suite = Get-SqlApiRetrySuite -Context $Context + $cases = @($suite.SelectNodes('testcase')) + if ($cases.Count -ne $Context.TestCount -or $cases.Count -eq 0) { + throw "Incomplete JUnit codeunit: expected $($Context.TestCount) cases, found $($cases.Count)." + } + $failures = @($suite.SelectNodes('testcase/failure')) + if ($failures.Count -eq 0 -or $suite.SelectNodes('.//error').Count -gt 0) { + return + } + $requestIds = @() + foreach ($failure in $failures) { + $message = $failure.GetAttribute('message') + if ($message -notmatch 'GET request failed\. Response code is 500 \(InternalServerError\)' -or + $message -notmatch 'Object reference not set to an instance of an object\.' -or + $message -notmatch 'CorrelationId:\s*([0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})(?![0-9a-f-])') { + return + } + $requestIds += $Matches[1] + } + # Refuse malformed/partial results rather than overlooking an unrepresented failure. + foreach ($case in $cases) { + if ($case.GetAttribute('result') -eq 'Fail' -and $case.SelectNodes('failure').Count -ne 1) { + return + } + } + + $finishedUtc = [datetime]::UtcNow + $events = @(Get-SqlApiRetryEvents -ContainerName $Context.ContainerName ` + -StartedUtc $Context.StartedUtc -FinishedUtc $finishedUtc) + $matchedEvents = @() + foreach ($requestId in $requestIds) { + $matchesForRequest = @() + foreach ($eventText in $events) { + [xml]$eventXml = $eventText + $ns = [System.Xml.XmlNamespaceManager]::new($eventXml.NameTable) + $ns.AddNamespace('e', 'http://schemas.microsoft.com/win/2004/08/events/event') + $system = $eventXml.SelectSingleNode('/e:Event/e:System', $ns) + $provider = $system.SelectSingleNode('e:Provider', $ns).GetAttribute('Name') + $eventId = $system.SelectSingleNode('e:EventID', $ns).InnerText + $time = [datetime]::Parse($system.SelectSingleNode('e:TimeCreated', $ns).GetAttribute('SystemTime')).ToUniversalTime() + $text = ($eventXml.SelectNodes('/e:Event/e:EventData/e:Data', $ns) | + ForEach-Object { $_.InnerText }) -join "`n" + if ($provider -match '^MicrosoftDynamicsNavServer\$' -and $eventId -eq '701' -and + $time -ge $Context.StartedUtc -and $time -le $finishedUtc -and + $text -match "(?m)^ClientSessionId:\s*$([regex]::Escape($requestId))\s*$" -and + $text -match 'RootException: NullReferenceException' -and + $text -match 'at Microsoft\.Dynamics\.Nav\.Runtime\.NavSqlConnectionScope\.AcquireSqlConnectionFromPool\(' -and + $text -match 'at Microsoft\.Dynamics\.Nav\.XmlMetadata\.MetadataProvider\.GetRelativeHelpUrl\(' -and + $text -match 'at Microsoft\.Dynamics\.Nav\.Service\.OData\.V4\.PageDataProvider\.GetNavRecordDataAsync\(') { + $matchesForRequest += [string]$eventText + } + } + if ($matchesForRequest.Count -eq 0) { + Write-Host "::warning::SQL API retry not eligible: no matching NST event for request '$requestId'." + return + } + $matchedEvents += $matchesForRequest + } + $evidence = [PSCustomObject]@{ + ContainerName = $Context.ContainerName + Tenant = $Context.Tenant + CodeunitId = $Context.CodeunitId + StartedUtc = $Context.StartedUtc.ToString('o') + FinishedUtc = $finishedUtc.ToString('o') + RequestIds = @($requestIds | Select-Object -Unique) + OriginalSuite = $suite.OuterXml + Events = @($matchedEvents | Select-Object -Unique) + TestCases = @($cases | ForEach-Object { + [PSCustomObject]@{ Name = $_.GetAttribute('name'); Skipped = ($null -ne $_.SelectSingleNode('skipped')) } + }) + } + $folder = Join-Path ([System.IO.Path]::GetDirectoryName($Context.ResultFiles.JUnitResultFileName)) 'SqlApiRetryEvidence' + if ($Context.PSObject.Properties['OutputDirectory'] -and $Context.OutputDirectory) { + $folder = Join-Path $Context.OutputDirectory 'SqlApiRetryEvidence' + } + $null = New-Item -ItemType Directory -Path $folder -Force -ErrorAction Stop + $evidenceFile = Join-Path $folder "$($Context.Tenant)-$($Context.CodeunitId)-$([guid]::NewGuid().ToString('N')).json" + $evidence | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $evidenceFile -Encoding utf8 -ErrorAction Stop + Write-Host "::warning::SQL API pool failure confirmed for codeunit $($Context.CodeunitId) on '$($Context.Tenant)'; requests: $($evidence.RequestIds -join ', '). Original evidence: $evidenceFile. Only the retry arm may authorize a single clean retry." + return $evidence + } catch { + Write-Host "::warning::SQL API retry evidence unavailable; preserving test failure: $($_.Exception.Message)" + return + } +} + +<# +.SYNOPSIS + Requires a SQL retry to preserve the original test names and skip status without failures. +#> +function Test-SqlApiRetryResult { + param( + $Context, + [array]$ExpectedTests + ) + + try { + $suite = Get-SqlApiRetrySuite -Context $Context + $cases = @($suite.SelectNodes('testcase')) + if ($cases.Count -ne $ExpectedTests.Count -or $suite.SelectNodes('.//failure | .//error').Count -gt 0) { + throw 'The retry did not produce a complete, passing codeunit.' + } + foreach ($expected in $ExpectedTests) { + $actual = @($cases | Where-Object { $_.GetAttribute('name') -ceq $expected.Name }) + if ($actual.Count -ne 1 -or + ($null -ne $actual[0].SelectSingleNode('skipped')) -ne $expected.Skipped -or + $actual[0].GetAttribute('result') -eq 'Fail') { + throw "Retry result missing, duplicated, failed or changed skip status for '$($expected.Name)'." + } + } + return $true + } catch { + Write-Host "::warning::SQL API retry remains failed: $($_.Exception.Message)" + return $false + } +} + +function Test-SqlApiExperimentSelection { + param($Context, [ValidateSet('control', 'warmup', 'retry')][string]$Experiment) + if ([string]$Context.CodeunitId -ne '148318') { return $true } + try { + $suite = Get-SqlApiRetrySuite -Context $Context + $target = @($suite.SelectNodes('testcase') | Where-Object { + ($_.GetAttribute('name') -split '\.')[-1] -ceq 'CapabilitiesProjectsEnabledViaAPI' + }) + if ($target.Count -ne 1) { throw 'Expected exactly one target method in Capabilities results.' } + if ($null -ne $target[0].SelectSingleNode('skipped')) { + throw "Target method must remain enabled in $Experiment." + } + return $true + } catch { + Write-Host "::warning::Experiment selection verification failed: $($_.Exception.Message)" + return $false + } +} + +Export-ModuleMember -Function Get-SqlApiTestRetryEvidence, Test-SqlApiRetryResult, Test-SqlApiExperimentSelection diff --git a/build/scripts/SqlResetPilot/CompaniesProbe.Tests.ps1 b/build/scripts/SqlResetPilot/CompaniesProbe.Tests.ps1 new file mode 100644 index 00000000000..6fdcbcf79af --- /dev/null +++ b/build/scripts/SqlResetPilot/CompaniesProbe.Tests.ps1 @@ -0,0 +1,76 @@ +BeforeAll { + function global:Get-BcContainerServerConfiguration { param($ContainerName) $null = $ContainerName; throw 'Live call forbidden.' } + function global:Get-BcContainerIpAddress { param($containerName) $null = $containerName; throw 'Live call forbidden.' } + Import-Module (Join-Path $PSScriptRoot 'Lifecycle.psm1') -Force +} + +Describe 'External authenticated companies probe' { + BeforeEach { + $script:tenants = @('default','tenant2','tenant3','tenant4') | ForEach-Object { + [PSCustomObject]@{ Id = $_; DatabaseName = $_ } + } + $password = [Security.SecureString]::new() + foreach ($character in 'test-only-marker'.ToCharArray()) { $password.AppendChar($character) } + $script:credential = [PSCredential]::new('fixture', $password) + Initialize-SqlResetPilot 'owned' $script:tenants 'control' '123' $TestDrive + Complete-SqlResetPlan (Get-SqlResetPlan 'owned' 'tenant2' 'tenant2' 'default-test-template') + Mock Get-BcContainerServerConfiguration -ModuleName Lifecycle { + @{ ServerInstance = 'BC'; ODataServicesPort = 7048; ODataServicesSSLEnabled = 'false'; ClientServicesCredentialType = 'NavUserPassword' } + } + Mock Get-BcContainerIpAddress -ModuleName Lifecycle { '172.16.1.2' } + Mock Invoke-WebRequest -ModuleName Lifecycle { + @{ StatusCode = 200; Headers = @{ 'request-id' = @('server-correlation') }; Content = '{"value":[{"name":"My Company","id":"company-id"}]}' } + } + Mock Add-Content -ModuleName Lifecycle {} + } + It 'sends exactly one explicitly tenant-scoped preauthenticated HTTP request with retries disabled' { + Invoke-SqlPilotCompaniesProbe 'owned' 'tenant2' $script:credential 'My Company' + Should -Invoke Invoke-WebRequest -ModuleName Lifecycle -Times 1 -Exactly -ParameterFilter { + $Uri -eq 'http://172.16.1.2:7048/BC/api/v2.0/companies?tenant=tenant2' -and + $Authentication -eq 'Basic' -and $Credential.UserName -eq 'fixture' -and + $MaximumRetryCount -eq 0 -and $MaximumRedirection -eq 0 -and $TimeoutSec -eq 60 -and $SkipHttpErrorCheck + } + Should -Invoke Add-Content -ModuleName Lifecycle -Times 1 -Exactly -ParameterFilter { + $Value -match '"status":200' -and $Value -match '"passed":true' -and + $Value -match 'server-correlation' -and $Value -notmatch 'fixture|test-only-marker' + } + } + It 'treats HTTP failures as terminal without logging response content' { + Mock Invoke-WebRequest -ModuleName Lifecycle { + @{ StatusCode = 500; Headers = @{}; Content = 'sensitive-response-marker' } + } + { Invoke-SqlPilotCompaniesProbe 'owned' 'tenant2' $script:credential 'My Company' } | + Should -Throw '*No retry*' + Should -Invoke Invoke-WebRequest -ModuleName Lifecycle -Times 1 -Exactly + Should -Invoke Add-Content -ModuleName Lifecycle -Times 1 -Exactly -ParameterFilter { + $Value -match '"status":500' -and $Value -notmatch 'sensitive-response-marker|test-only-marker' + } + } + It 'rejects invalid JSON without another request' { + Mock Invoke-WebRequest -ModuleName Lifecycle { @{ StatusCode = 200; Headers = @{}; Content = 'invalid-json' } } + { Invoke-SqlPilotCompaniesProbe 'owned' 'tenant2' $script:credential 'My Company' } | Should -Throw + Should -Invoke Invoke-WebRequest -ModuleName Lifecycle -Times 1 -Exactly + } + It 'rejects missing expected company without another request' { + Mock Invoke-WebRequest -ModuleName Lifecycle { + @{ StatusCode = 200; Headers = @{}; Content = '{"value":[{"name":"Other","id":"id"}]}' } + } + { Invoke-SqlPilotCompaniesProbe 'owned' 'tenant2' $script:credential 'My Company' } | Should -Throw + Should -Invoke Invoke-WebRequest -ModuleName Lifecycle -Times 1 -Exactly + } + It 'redacts transport exception text and never retries' { + Mock Invoke-WebRequest -ModuleName Lifecycle { throw 'sensitive-exception-marker' } + { Invoke-SqlPilotCompaniesProbe 'owned' 'tenant2' $script:credential 'My Company' } | + Should -Throw '*sanitized companies-probes*' + Should -Invoke Invoke-WebRequest -ModuleName Lifecycle -Times 1 -Exactly + Should -Invoke Add-Content -ModuleName Lifecycle -Times 1 -Exactly -ParameterFilter { + $Value -notmatch 'sensitive-exception-marker|test-only-marker' + } + } + It 'refuses a foreign container, default tenant, or worker not yet restored' { + { Invoke-SqlPilotCompaniesProbe 'foreign' 'tenant2' $script:credential 'My Company' } | Should -Throw + { Invoke-SqlPilotCompaniesProbe 'owned' 'default' $script:credential 'My Company' } | Should -Throw + { Invoke-SqlPilotCompaniesProbe 'owned' 'tenant3' $script:credential 'My Company' } | Should -Throw + Should -Invoke Invoke-WebRequest -ModuleName Lifecycle -Times 0 + } +} diff --git a/build/scripts/SqlResetPilot/Comparison.Tests.ps1 b/build/scripts/SqlResetPilot/Comparison.Tests.ps1 new file mode 100644 index 00000000000..34263a8dc2e --- /dev/null +++ b/build/scripts/SqlResetPilot/Comparison.Tests.ps1 @@ -0,0 +1,123 @@ +BeforeAll { + Import-Module (Join-Path $PSScriptRoot 'Comparison.psm1') -Force +} + +Describe 'Exact balanced 300-cell comparison manifest' { + BeforeAll { + $script:cells = @(Get-SqlComparisonCell) + } + It 'contains exactly 300 unique identities and all 50 indices per arm and country' { + $script:cells.Count | Should -Be 300 + @($script:cells | ForEach-Object { "$($_.experiment)/$($_.country)/$($_.trial)" } | + Sort-Object -Unique).Count | Should -Be 300 + foreach ($arm in @('control', 'warmup', 'retry')) { + foreach ($country in @('W1', 'DE')) { + $indices = @($script:cells | Where-Object { $_.experiment -eq $arm -and $_.country -eq $country } | + Select-Object -ExpandProperty trial | Sort-Object) + ($indices -join ',') | Should -Be ((1..50) -join ',') + } + } + } + It 'splits into ten matrix-safe balanced batches and six-cell index blocks' { + foreach ($batch in 0..9) { + $selected = @($script:cells | Select-Object -Skip ($batch * 30) -First 30) + $selected.Count | Should -Be 30 + foreach ($group in @($selected | Group-Object experiment, country)) { + $group.Count | Should -Be 5 + } + } + foreach ($block in 0..49) { + $selected = @($script:cells | Select-Object -Skip ($block * 6) -First 6) + @($selected.trial | Sort-Object -Unique).Count | Should -Be 1 + @($selected | Group-Object experiment, country).Count | Should -Be 6 + } + } + It 'generates exactly one explicit replacement and no other cells' { + $cells = @(Get-SqlComparisonCell -Mode replacement -Arm retry -Country DE -Trial 50) + $cells.Count | Should -Be 1 + $cells[0].experiment | Should -Be 'retry' + $cells[0].country | Should -Be 'DE' + $cells[0].trial | Should -Be 50 + } + It 'rejects invalid replacement identities and mixed original selection' { + foreach ($trial in @('0', '51', '01', '-1', '1,2', '')) { + { Get-SqlComparisonCell -Mode replacement -Arm retry -Country DE -Trial $trial } | Should -Throw + } + { Get-SqlComparisonCell -Mode replacement -Arm A -Country DE -Trial 1 } | Should -Throw + { Get-SqlComparisonCell -Mode replacement -Arm retry -Country US -Trial 1 } | Should -Throw + { Get-SqlComparisonCell -Mode originals -Arm control } | Should -Throw + } + It 'preserves original probe implementation and compiled source byte-for-byte' { + $root = Resolve-Path (Join-Path $PSScriptRoot '..\..\..') + $diff = git -C $root diff fcc1776c6b165199dd66e4227675b1cc31da7a8f -- ` + build/scripts/SqlResetPilot/Lifecycle.psm1 build/scripts/SqlResetPilot/CompaniesProbe.Tests.ps1 ` + build/scripts/RunTestsInBcContainer.ps1 .github/AL-Go-Settings.json build/projects src + $LASTEXITCODE | Should -Be 0 + $diff | Should -BeNullOrEmpty + } + It 'keeps exact immutable artifact pairs consistent with runtime preparation' { + $prepare = Get-Content (Join-Path $PSScriptRoot 'Prepare.ps1') -Raw + $pins = @(Get-SqlComparisonArtifact) + $pins.Count | Should -Be 4 + foreach ($pin in $pins) { + $prepare | Should -Match ([regex]::Escape($pin.id)) + $prepare | Should -Match ([regex]::Escape($pin.digest)) + } + } +} + +Describe 'Only authoritative original communication failures qualify for replacement' { + BeforeEach { + $script:sha = '1111111111111111111111111111111111111111' + $script:run = [PSCustomObject]@{ + id = 100; head_sha = $script:sha; head_branch = 'features/646383-sql-api-300-trial-comparison' + event = 'workflow_dispatch'; run_attempt = 1; path = '.github/workflows/CICD.yaml' + display_title = 'SQL API 300 comparison - originals' + } + + $script:job = [PSCustomObject]@{ + id = 200; run_id = 100; conclusion = 'failure'; status = 'completed' + name = 'Batch01 / Trial warmup/DE/3' + } + $script:annotations = @([PSCustomObject]@{ + annotation_level = 'failure' + message = 'The self-hosted runner: isolated-runner lost communication with the server.' + }) + $script:cell = [PSCustomObject]@{ experiment = 'warmup'; country = 'DE'; trial = 3 } + } + It 'preserves the exact original run, job, revision and annotation' { + $record = Assert-SqlComparisonReplacement $script:run $script:job $script:annotations $script:cell $script:sha + $record.runId | Should -Be '100' + $record.jobId | Should -Be '200' + $record.trialIdentity | Should -Be 'warmup/DE/3' + $record.workflowSha | Should -Be $script:sha + $record.annotation.Count | Should -Be 1 + } + It 'rejects SQL or ordinary test failures even if caller requests replacement' { + $script:annotations[0].message = 'GET request failed: 500. AcquireSqlConnectionFromPool NullReferenceException' + { Assert-SqlComparisonReplacement $script:run $script:job $script:annotations $script:cell $script:sha } | Should -Throw + { Assert-SqlComparisonReplacement $script:run $script:job @() $script:cell $script:sha } | Should -Throw + } + It 'rejects original run drift: ' -ForEach @( + @{ Property = 'head_sha'; Value = '2222222222222222222222222222222222222222' } + @{ Property = 'head_branch'; Value = 'features/646383-sql-api-de3-communication-replay' } + @{ Property = 'event'; Value = 'pull_request' } + @{ Property = 'run_attempt'; Value = 2 } + @{ Property = 'path'; Value = '.github/workflows/Other.yaml' } + @{ Property = 'display_title'; Value = 'SQL API 300 comparison - replacement' } + ) { + $script:run.$Property = $Value + { Assert-SqlComparisonReplacement $script:run $script:job $script:annotations $script:cell $script:sha } | Should -Throw + } + It 'rejects wrong, skipped, cancelled or successful jobs: /' -ForEach @( + @{ Property = 'run_id'; Value = 101 } + @{ Property = 'name'; Value = 'Batch01 / Trial retry/DE/3' } + @{ Property = 'conclusion'; Value = 'success' } + @{ Property = 'conclusion'; Value = 'cancelled' } + @{ Property = 'conclusion'; Value = 'skipped' } + @{ Property = 'status'; Value = 'in_progress' } + ) { + $script:job.$Property = $Value + { Assert-SqlComparisonReplacement $script:run $script:job $script:annotations $script:cell $script:sha } | Should -Throw + } +} diff --git a/build/scripts/SqlResetPilot/Comparison.psm1 b/build/scripts/SqlResetPilot/Comparison.psm1 new file mode 100644 index 00000000000..ef5334bc600 --- /dev/null +++ b/build/scripts/SqlResetPilot/Comparison.psm1 @@ -0,0 +1,102 @@ +function Get-SqlComparisonCell { + param([ValidateSet('originals', 'replacement')][string]$Mode = 'originals', + [string]$Arm, [string]$Country, [string]$Trial) + if ($Mode -eq 'replacement') { + if ($Arm -notin @('control', 'warmup', 'retry') -or $Country -notin @('W1', 'DE') -or + $Trial -notmatch '^(?:[1-9]|[1-4][0-9]|50)$') { throw 'Invalid replacement identity.' } + return [PSCustomObject]@{ experiment = $Arm; country = $Country; trial = [int]$Trial } + } + if ($Arm -or $Country -or $Trial) { throw 'Original schedule cannot contain replacement selection.' } + foreach ($index in 1..50) { + # Rotate queue order across indices without changing balanced six-cell blocks. + $countries = if ($index % 2) { @('W1', 'DE') } else { @('DE', 'W1') } + $arms = @('control', 'warmup', 'retry') + foreach ($location in $countries) { + foreach ($offset in 0..2) { + [PSCustomObject]@{ + experiment = $arms[($index - 1 + $offset) % 3] + country = $location + trial = $index + } + } + } + } +} + +function Assert-SqlComparisonReplacement { + param($Run, $Job, [array]$Annotations, $Cell, [string]$ExpectedSha) + $identity = "$($Cell.experiment)/$($Cell.country)/$($Cell.trial)" + if ($Run.head_sha -ne $ExpectedSha -or + $Run.head_branch -ne 'features/646383-sql-api-300-trial-comparison' -or + $Run.event -ne 'workflow_dispatch' -or $Run.run_attempt -ne 1 -or + $Run.path -ne '.github/workflows/CICD.yaml' -or + $Run.display_title -ne 'SQL API 300 comparison - originals' -or + $Job.run_id -ne $Run.id -or $Job.conclusion -ne 'failure' -or $Job.status -ne 'completed' -or + $Job.name -notmatch "(?:^| / )Trial $([regex]::Escape($identity))$") { + throw 'Replacement must identify a failed original cell from this exact comparison revision.' + } + $communication = @($Annotations | Where-Object { + $_.annotation_level -eq 'failure' -and + $_.message -match '(?is)self-hosted runner.*lost communication with (?:the )?server' + }) + if ($communication.Count -eq 0) { throw 'No authoritative runner-communication annotation; no replacement authorized.' } + [PSCustomObject]@{ + runId = [string]$Run.id; jobId = [string]$Job.id; trialIdentity = $identity + event = $Run.event; runAttempt = $Run.run_attempt; workflow = $Run.path + workflowSha = $Run.head_sha; annotation = @($communication.message) + reason = 'Confirmed GitHub runner communication failure; retained separately from original results' + } +} + +function Get-SqlComparisonArtifact { + @( + @{ country = 'W1'; kind = 'apps'; id = '11374170356'; digest = '683343673e6efeb7699734b250d2ee5004d2d83fe08e57f324c4c645c09612db' } + @{ country = 'W1'; kind = 'tests'; id = '11374145359'; digest = 'f75ce06920437328e5d79a5512eddcc2425624bb696c339c108478c83554171d' } + @{ country = 'DE'; kind = 'apps'; id = '11376415128'; digest = '409af00bb5e6922224626f94a4d4f5625f4a9bf13b9398e84cc101a41a313dd5' } + @{ country = 'DE'; kind = 'tests'; id = '11375174896'; digest = '4e1edde77089e0b586679b168f11123a8181a99c63c3a82b42323503340a5d3b' } + ) +} + +function Assert-SqlComparisonSnapshot { + param([string]$Directory, [ValidateSet('W1', 'DE')][string]$Country) + $proof = @(Get-Content (Join-Path $Directory 'artifact-proof.json') -Raw -ErrorAction Stop | ConvertFrom-Json) + if ($proof.Count -ne 2) { throw 'Snapshot must contain the two original country artifacts.' } + foreach ($pin in @(Get-SqlComparisonArtifact | Where-Object country -eq $Country)) { + $entry = @($proof | Where-Object { $_.pin.id -eq $pin.id }) + if ($entry.Count -ne 1 -or $entry[0].metadata.id -ne $pin.id -or + $entry[0].metadata.expired -or $entry[0].metadata.workflow_run.id -ne 37372848860 -or + $entry[0].metadata.workflow_run.head_sha -ne 'c4953dceffe02a017adad34973e1955017bf5d20' -or + $entry[0].metadata.digest -ne "sha256:$($pin.digest)" -or + (Get-FileHash (Join-Path $Directory "$($pin.id).zip") -Algorithm SHA256 -ErrorAction Stop).Hash -ne $pin.digest) { + throw 'Immutable snapshot archive or original provenance differs from the pinned source.' + } + } + return $proof +} + +function Save-SqlComparisonSnapshot { + param([string]$ArtifactId, [string]$RunId, [string]$HeadSha, + [ValidateSet('W1', 'DE')][string]$Country, [string]$Directory) + if ($ArtifactId -notmatch '^\d{1,20}$' -or $RunId -notmatch '^\d{1,20}$' -or -not $env:GH_TOKEN) { + throw 'Explicit snapshot identity and Actions credential are required.' + } + $headers = @{ Authorization = "Bearer $env:GH_TOKEN"; Accept = 'application/vnd.github+json' } + $uri = "https://api.github.com/repos/microsoft/BCApps/actions/artifacts/$ArtifactId" + $metadata = Invoke-RestMethod $uri -Headers $headers + if ($metadata.expired -or $metadata.workflow_run.id -ne $RunId -or + $metadata.workflow_run.head_sha -ne $HeadSha -or + $metadata.name -ne "sql-api-comparison-packages-$Country-$RunId" -or + $metadata.digest -notmatch '^sha256:([0-9a-f]{64})$') { + throw 'Snapshot must be the immutable country package archive from this comparison revision.' + } + $digest = $Matches[1] + $null = New-Item -ItemType Directory -Path $Directory -Force + $zip = "$Directory.zip" + Invoke-WebRequest "$uri/zip" -Headers $headers -OutFile $zip -UseBasicParsing + if ((Get-FileHash $zip -Algorithm SHA256).Hash -ne $digest) { throw 'Snapshot transport hash mismatch.' } + Expand-Archive $zip $Directory -Force + Assert-SqlComparisonSnapshot -Directory $Directory -Country $Country +} + +Export-ModuleMember -Function Get-SqlComparisonCell, Assert-SqlComparisonReplacement, Get-SqlComparisonArtifact, + Assert-SqlComparisonSnapshot, Save-SqlComparisonSnapshot diff --git a/build/scripts/SqlResetPilot/ComparisonRunner.Tests.ps1 b/build/scripts/SqlResetPilot/ComparisonRunner.Tests.ps1 new file mode 100644 index 00000000000..882883aff99 --- /dev/null +++ b/build/scripts/SqlResetPilot/ComparisonRunner.Tests.ps1 @@ -0,0 +1,185 @@ +$discoveryArm = $env:BC_SQL_PILOT_ARM +try { + $env:BC_SQL_PILOT_ARM = 'control' + Import-Module (Join-Path $PSScriptRoot '..\ParallelTestExecution.psm1') -Force +} finally { + $env:BC_SQL_PILOT_ARM = $discoveryArm +} +Describe 'Exact manual three-arm comparison isolation' { + BeforeEach { + $script:saved = @{} + foreach ($key in @('GITHUB_REPOSITORY','GITHUB_REF','GITHUB_EVENT_NAME','GITHUB_RUN_ATTEMPT', + 'BC_SQL_PILOT_ARM','BC_SQL_API_EXPERIMENT','BC_SQL_PILOT_OUTPUT')) { + $script:saved[$key] = [Environment]::GetEnvironmentVariable($key) + } + $env:GITHUB_REPOSITORY = 'microsoft/BCApps' + $env:GITHUB_REF = 'refs/heads/features/646383-sql-api-300-trial-comparison' + $env:GITHUB_EVENT_NAME = 'workflow_dispatch' + $env:GITHUB_RUN_ATTEMPT = '1' + $env:BC_SQL_PILOT_ARM = 'control' + $env:BC_SQL_API_EXPERIMENT = 'retry' + $env:BC_SQL_PILOT_OUTPUT = $TestDrive + } + AfterEach { + foreach ($key in $script:saved.Keys) { [Environment]::SetEnvironmentVariable($key, $script:saved[$key]) } + } + InModuleScope ParallelTestExecution { + Context 'Runner and scheduler hooks' { + BeforeEach { + Mock Get-ChildItem { @() } + Mock Start-Sleep {} + Mock Start-TestJob { [PSCustomObject]@{ Id = 1 } } + $script:state = [PSCustomObject]@{ + jobs = @(); hasFailures = $false; transient = @(); retried = @{}; retryTenant = @{}; sqlRetryEvidence = @{} + } + $script:item = [PSCustomObject]@{ + Key = 'Test App::148318'; AppName = 'Test App'; AppId = 'id' + CodeunitId = '148318'; CodeunitName = 'Capabilities'; TestCount = 3 + } + $script:tenant = [PSCustomObject]@{ Id = 'tenant2'; DatabaseName = 'tenant2' } + $script:parameters = @{ + containerName = 'owned'; JUnitResultFileName = (Join-Path $TestDrive 'TestResults.xml') + credential = [PSCredential]::Empty; companyName = 'My Company' + } + } + It 'never adds an exclusion in any arm' { + foreach ($arm in @('control', 'warmup', 'retry')) { + $env:BC_SQL_API_EXPERIMENT = $arm + @(Get-DisabledTestsForApp 'Test App').Count | Should -Be 0 + } + } + It 'enables app and companies warmup only in the two warmup arms' { + $env:BC_SQL_API_EXPERIMENT = 'control' + Test-SqlApiWarmupEnabled | Should -BeFalse + foreach ($arm in @('warmup', 'retry')) { + $env:BC_SQL_API_EXPERIMENT = $arm + Test-SqlApiWarmupEnabled | Should -BeTrue + } + } + It 'cannot activate on ' -ForEach @( + @{ Kind = 'PR'; Key = 'GITHUB_EVENT_NAME'; Value = 'pull_request' } + @{ Kind = 'another branch'; Key = 'GITHUB_REF'; Value = 'refs/heads/main' } + @{ Kind = 'rerun'; Key = 'GITHUB_RUN_ATTEMPT'; Value = '2' } + @{ Kind = 'other repository'; Key = 'GITHUB_REPOSITORY'; Value = 'other/BCApps' } + @{ Kind = 'fresh SQL'; Key = 'BC_SQL_PILOT_ARM'; Value = 'fresh' } + ) { + [Environment]::SetEnvironmentVariable($Key, $Value) + Test-SqlApiExperiment | Should -BeFalse + } + It 'queues only a confirmed retry-arm failure and never a generic transient' { + $result = [PSCustomObject]@{ Outcome = 'SqlPoolRetry'; AppName = $script:item.Key; Tenant = 'tenant2'; SqlRetryEvidence = @{ TestCases = @('one') } } + Register-TestJobOutcome $result $script:state + $script:state.transient.Count | Should -Be 1 + $script:state.hasFailures | Should -BeFalse + $script:state.retried[$script:item.Key] = $true + Register-TestJobOutcome $result $script:state + $script:state.transient.Count | Should -Be 1 + $script:state.hasFailures | Should -BeTrue + } + It 'never queues SQL retry in control or warmup' { + foreach ($arm in @('control', 'warmup')) { + $env:BC_SQL_API_EXPERIMENT = $arm + Register-TestJobOutcome ([PSCustomObject]@{ Outcome = 'SqlPoolRetry' }) $script:state + $script:state.hasFailures | Should -BeTrue + $script:state.transient.Count | Should -Be 0 + } + } + It 'restores control workers but performs no companies probe' { + $env:BC_SQL_API_EXPERIMENT = 'control' + Mock Reset-BcTestTenant {} + Mock Invoke-SqlPilotCompaniesProbe { throw 'Control must never probe.' } + Mock Start-RequiredDisabledDispatch {} + Mock Wait-ForAllTestJobs {} + Invoke-RequiredDisabledTestExecution $script:parameters @($script:item) @($script:tenant) ` + 'default-test-template' 'runner.ps1' 'IntegrationTest' | Should -BeTrue + Should -Invoke Reset-BcTestTenant -Times 1 -Exactly + Should -Invoke Invoke-SqlPilotCompaniesProbe -Times 0 + Should -Invoke Start-RequiredDisabledDispatch -Times 1 -Exactly + } + It 'retries the full CU without BCH ReRun and writes to a separate result file' { + $script:state.sqlRetryEvidence[$script:item.Key] = @{ TestCases = @(@{ Name = 'one'; Skipped = $false }) } + Start-RequiredDisabledDispatch $script:parameters $script:item $script:tenant 'runner.ps1' 'IntegrationTest' $script:state 'Re-dispatching' + Should -Invoke Start-TestJob -Times 1 -Exactly -ParameterFilter { + -not $parameters.ContainsKey('ReRun') -and $parameters.testCodeunit -eq '148318' -and + $fileSuffix -eq 'tenant2-sqlretry-148318' -and $skipAutomaticDisabledPass + } + $script:state.jobs[0].SqlRetryContext.Attempt | Should -Be 2 + $script:state.jobs[0].SqlRetryContext.ResultFiles.JUnitResultFileName | Should -Match 'tenant2-sqlretry-148318' + } + It 'restores and probes again before a once-only retry and drains failures' { + $script:order = [Collections.Generic.List[string]]::new() + $script:waits = 0 + Mock Reset-BcTestTenant { $script:order.Add('restore') } + Mock Invoke-SqlPilotCompaniesProbe { $script:order.Add('probe') } + Mock Start-RequiredDisabledDispatch { $script:order.Add("dispatch:$Verb") } + Mock Wait-ForAllTestJobs { + $script:waits++ + if ($script:waits -eq 1) { + $state.sqlRetryEvidence[$script:item.Key] = @{ TestCases = @('one') } + $state.transient = @([PSCustomObject]@{ Key = $script:item.Key; Tenant = 'tenant2' }) + } else { $state.hasFailures = $true } + } + Invoke-RequiredDisabledTestExecution $script:parameters @($script:item) @($script:tenant) ` + 'default-test-template' 'runner.ps1' 'IntegrationTest' | Should -BeFalse + ($script:order -join ',') | Should -Be 'restore,probe,dispatch:Dispatching,restore,probe,dispatch:Re-dispatching' + $script:waits | Should -Be 2 + } + It 'preserves first failure and separate full retry, merging only validated recovery' { + Mock Receive-Job {} -RemoveParameterType Job + Mock Remove-Job {} -RemoveParameterType Job + Mock Get-SqlApiTestRetryEvidence { @{ TestCases = @(@{ Name = 'CapabilitiesProjectsEnabledViaAPI'; Skipped = $false }) } } + $originalPath = Join-Path $TestDrive 'TestResults-tenant2.xml' + $retryPath = Join-Path $TestDrive 'TestResults-tenant2-sqlretry-148318.xml' + $original = '' + $passed = '' + $original | Set-Content $originalPath + $context = [PSCustomObject]@{ + CodeunitId = 148318; Tenant = 'tenant2'; StartedUtc = [datetime]::UtcNow + TestCount = 1; Attempt = 1; ResultFiles = @{ JUnitResultFileName = $originalPath } + FinalResultFiles = @{ JUnitResultFileName = $originalPath }; OutputDirectory = $TestDrive + } + $entry = [PSCustomObject]@{ appName = $script:item.Key; tenant = 'tenant2'; SqlRetryContext = $context; SqlRetryExpectedTests = @() } + $firstResult = Receive-TestJobResult $entry @{ Id = 91; State = 'Failed' } @{} + $firstResult.Outcome | Should -Be 'SqlPoolRetry' + $firstSaved = Join-Path $TestDrive 'test-attempts\tenant2-148318-1\JUnitResultFileName' + (Get-Content $firstSaved -Raw).Trim() | Should -Be $original + $passed | Set-Content $retryPath + $context.Attempt = 2 + $context.ResultFiles = @{ JUnitResultFileName = $retryPath } + $entry.SqlRetryExpectedTests = $firstResult.SqlRetryEvidence.TestCases + (Receive-TestJobResult $entry @{ Id = 92; State = 'Completed' } @{ $script:item.Key = $true }).Outcome | Should -Be 'Passed' + ([xml](Get-Content $originalPath -Raw)).SelectNodes('//failure').Count | Should -Be 0 + (Get-Content $firstSaved -Raw).Trim() | Should -Be $original + Test-Path (Join-Path $TestDrive 'test-attempts\tenant2-148318-2\JUnitResultFileName') | Should -BeTrue + Should -Invoke Get-SqlApiTestRetryEvidence -Times 1 -Exactly + } + It 'does not classify stopped or already-retried failures as eligible' { + Mock Receive-Job {} -RemoveParameterType Job + Mock Remove-Job {} -RemoveParameterType Job + Mock Get-SqlApiTestRetryEvidence { throw 'Evidence classifier must not be called.' } + Mock Test-SqlApiExperimentSelection { $true } + $context = [PSCustomObject]@{ + CodeunitId = 148318; Tenant = 'tenant2'; StartedUtc = [datetime]::UtcNow + TestCount = 1; Attempt = 2; ResultFiles = @{} + } + $entry = [PSCustomObject]@{ appName = $script:item.Key; tenant = 'tenant2'; SqlRetryContext = $context; SqlRetryExpectedTests = @() } + foreach ($jobState in @('Stopped','Failed')) { + (Receive-TestJobResult $entry @{ Id = 91; State = $jobState } @{ $script:item.Key = $true }).Outcome | Should -Be 'Failed' + } + Should -Invoke Get-SqlApiTestRetryEvidence -Times 0 + } + It 'rejects inherited exclusions in actual JUnit in every arm' { + $path = Join-Path $TestDrive 'selection.xml' + $context = [PSCustomObject]@{ CodeunitId = 148318; ResultFiles = @{ JUnitResultFileName = $path } } + '' | Set-Content $path + foreach ($arm in @('control', 'warmup', 'retry')) { + Test-SqlApiExperimentSelection $context $arm | Should -BeFalse + } + '' | Set-Content $path + foreach ($arm in @('control', 'warmup', 'retry')) { + Test-SqlApiExperimentSelection $context $arm | Should -BeTrue + } + } + } + } +} diff --git a/build/scripts/SqlResetPilot/ContainerPreflight.ps1 b/build/scripts/SqlResetPilot/ContainerPreflight.ps1 new file mode 100644 index 00000000000..3a1aa2675a0 --- /dev/null +++ b/build/scripts/SqlResetPilot/ContainerPreflight.ps1 @@ -0,0 +1,34 @@ +param([hashtable]$Parameters) +$ErrorActionPreference = 'Stop' +Import-Module (Join-Path $PSScriptRoot 'PlatformUptake.psm1') -Force +Assert-SqlPlatformUptakeContext -Cell +if (-not $env:BC_SQL_PILOT_OUTPUT) { throw 'Missing owned output directory.' } +$expectedName = "bcbuildprojectsTestApps$($env:BC_SQL_PILOT_COUNTRY)Uptake$($env:BC_SQL_PILOT_TRIAL)$($env:BC_SQL_API_EXPERIMENT)$($env:GITHUB_RUN_ID)" +if ($Parameters.ContainerName -ne $expectedName -or (Test-BcContainer -containerName $expectedName)) { + throw 'Pilot container name is unexpected or already exists. No replacement is authorized.' +} +$module = Get-Module BcContainerHelper -ErrorAction Stop +$helperVersion = & $module { $bcContainerHelperVersion } +if ($helperVersion -ne '6.1.19-preview2811389') { throw "Wrong BCH version: $helperVersion" } +$settings = $env:Settings | ConvertFrom-Json +if ($settings.country -ne $env:BC_SQL_PILOT_COUNTRY -or $settings.testType -ne 'IntegrationTest' -or + $settings.numberOfTenantsForTesting -ne 4 -or $settings.companyName -ne 'My Company' -or + -not $settings.enableCleanTestCodeunitExecution -or $settings.enableTaskScheduler) { + throw 'Effective country Integration settings differ from the predeclared experiment.' +} +if (-not (Get-Command New-BcContainer).Parameters.ContainsKey('useGenericImage')) { + throw 'Exact BCH does not expose the supported generic-image parameter.' +} +$Parameters.useGenericImage = 'mcr.microsoft.com/businesscentral@sha256:c899d12093ad7bbdbfd08ccc0e6294e0f98c682c7e35db4ecfbca345fb068492' +if ($Parameters.platformArtifactUrl -ne 'https://bcinsider-fvh2ekdjecfjd6gk.b02.azurefd.net/platform/30.0.56092.0/platform') { + throw 'Platform artifact is not the pinned source platform.' +} +@{ + container = $expectedName; runId = $env:GITHUB_RUN_ID; arm = $env:BC_SQL_PILOT_ARM + country = $env:BC_SQL_PILOT_COUNTRY; trial = $env:BC_SQL_PILOT_TRIAL + experiment = $env:BC_SQL_API_EXPERIMENT + helperVersion = $helperVersion; image = $Parameters.useGenericImage + imageGenericTag = '1.0.2.128'; platform = '30.0.56092.0' + hostOS = [Environment]::OSVersion.Version.ToString() + registeredUtc = [DateTime]::UtcNow.ToString('o') +} | ConvertTo-Json | Set-Content (Join-Path $env:BC_SQL_PILOT_OUTPUT 'container-ownership.json') -Encoding UTF8 diff --git a/build/scripts/SqlResetPilot/Finalize.Tests.ps1 b/build/scripts/SqlResetPilot/Finalize.Tests.ps1 new file mode 100644 index 00000000000..32c8ad29c12 --- /dev/null +++ b/build/scripts/SqlResetPilot/Finalize.Tests.ps1 @@ -0,0 +1,97 @@ +function global:Test-BcContainer { param($containerName) throw 'Live container call forbidden.' } +function global:Get-BcContainerEventLog { param($containerName, [switch]$doNotOpen) throw 'Live container call forbidden.' } +function global:Remove-BcContainer { param($containerName) throw 'Live container call forbidden.' } + +Describe 'SQL pilot final cleanup ownership' { + BeforeEach { + $script:oldWorkspace = $env:GITHUB_WORKSPACE + $script:oldRun = $env:GITHUB_RUN_ID + $script:oldArm = $env:BC_SQL_PILOT_ARM + $script:oldHelper = $env:BcContainerHelperPath + $script:oldCountry = $env:BC_SQL_PILOT_COUNTRY + $script:oldTrial = $env:BC_SQL_PILOT_TRIAL + $script:oldExperiment = $env:BC_SQL_API_EXPERIMENT + $env:GITHUB_WORKSPACE = $PSScriptRoot + $env:GITHUB_RUN_ID = '123' + $env:BC_SQL_PILOT_ARM = 'control' + $env:BC_SQL_PILOT_COUNTRY = 'DE' + $env:BC_SQL_PILOT_TRIAL = '2' + $env:BC_SQL_API_EXPERIMENT = 'control' + $env:BcContainerHelperPath = Join-Path $PSScriptRoot 'BcContainerHelper.ps1' + Mock Import-Module {} + Mock Test-Path { $true } + Mock Get-Content { '{"runId":"123","arm":"control","country":"DE","trial":"2","experiment":"control","container":"bcbuildprojectsTestAppsDEUptake2control123"}' } + Mock Get-ChildItem {} + Mock New-Item {} + Mock Copy-Item {} + Mock Set-Content {} + $global:sqlPilotTestContainerExists = $true + Mock Test-BcContainer { $global:sqlPilotTestContainerExists } + Mock Get-BcContainerEventLog { 'events.evtx' } + Mock Remove-BcContainer { $global:sqlPilotTestContainerExists = $false } + } + AfterEach { + $env:GITHUB_WORKSPACE = $script:oldWorkspace + $env:GITHUB_RUN_ID = $script:oldRun + $env:BC_SQL_PILOT_ARM = $script:oldArm + $env:BcContainerHelperPath = $script:oldHelper + $env:BC_SQL_PILOT_COUNTRY = $script:oldCountry + $env:BC_SQL_PILOT_TRIAL = $script:oldTrial + $env:BC_SQL_API_EXPERIMENT = $script:oldExperiment + Remove-Variable sqlPilotTestContainerExists -Scope Global + } + It 'exports before disposing only the registered container' { + & (Join-Path $PSScriptRoot 'Finalize.ps1') + Should -Invoke Get-BcContainerEventLog -Times 1 -Exactly -Scope It + Should -Invoke Remove-BcContainer -Times 1 -Exactly -Scope It -ParameterFilter { $containerName -eq 'bcbuildprojectsTestAppsDEUptake2control123' } + } + It 'still tears down if exporting fails and keeps that failure visible' { + Mock Get-BcContainerEventLog { throw 'event export failed' } + { & (Join-Path $PSScriptRoot 'Finalize.ps1') } | Should -Throw + Should -Invoke Remove-BcContainer -Times 1 -Exactly -Scope It + } + It 'collects root and nested runner results separately from warmup' { + Mock Get-ChildItem { [PSCustomObject]@{ FullName = 'TestResults.xml' } } + & (Join-Path $PSScriptRoot 'Finalize.ps1') + Should -Invoke Get-ChildItem -Times 1 -Exactly -Scope It -ParameterFilter { + $Path -like '*Test Apps DE Uptake2control\.buildartifacts' -and $Filter -eq 'TestResults*.xml' -and $File + } + Should -Invoke Copy-Item -Times 1 -Exactly -Scope It -ParameterFilter { + $Destination -like '*clean-results\buildartifacts' + } + Should -Invoke Copy-Item -Times 1 -Exactly -Scope It -ParameterFilter { + $Destination -like '*clean-results\project-root' + } + Should -Invoke Copy-Item -Times 0 -Exactly -Scope It -ParameterFilter { + $Destination -like '*sql-reset-pilot-output\warmup*' + } + } + It 'does not fail cleanup when nested runner results are absent' { + Mock Test-Path { $false } -ParameterFilter { $Path -like '*\.buildartifacts' } + & (Join-Path $PSScriptRoot 'Finalize.ps1') + Should -Invoke Get-ChildItem -Times 0 -Exactly -Scope It -ParameterFilter { + $Path -like '*\.buildartifacts' + } + Should -Invoke Remove-BcContainer -Times 1 -Exactly -Scope It + } + It 'refuses deletion if ownership was not recorded' { + Mock Test-Path { $false } + & (Join-Path $PSScriptRoot 'Finalize.ps1') + Should -Invoke Remove-BcContainer -Times 0 -Exactly -Scope It + } + It 'refuses deletion when run, arm or exact name differs' { + Mock Get-Content { '{"runId":"999","arm":"fresh","container":"shared"}' } + { & (Join-Path $PSScriptRoot 'Finalize.ps1') } | Should -Throw + Should -Invoke Remove-BcContainer -Times 0 -Exactly -Scope It + } + It 'refuses deletion of another trial in the same country and run' { + $env:BC_SQL_PILOT_TRIAL = '3' + { & (Join-Path $PSScriptRoot 'Finalize.ps1') } | Should -Throw + Should -Invoke Remove-BcContainer -Times 0 -Exactly -Scope It + } + It 'never deletes an original comparison container' { + Mock Get-Content { '{"runId":"123","arm":"control","country":"DE","trial":"2","experiment":"control","container":"bcbuildprojectsTestAppsDETrial2control123"}' } + { & (Join-Path $PSScriptRoot 'Finalize.ps1') } | Should -Throw + Should -Invoke Remove-BcContainer -Times 0 -Exactly -Scope It + } +} diff --git a/build/scripts/SqlResetPilot/Finalize.ps1 b/build/scripts/SqlResetPilot/Finalize.ps1 new file mode 100644 index 00000000000..46d4eb13de6 --- /dev/null +++ b/build/scripts/SqlResetPilot/Finalize.ps1 @@ -0,0 +1,42 @@ +$ErrorActionPreference = 'Stop' +$output = Join-Path $env:GITHUB_WORKSPACE 'sql-reset-pilot-output' +$ownershipPath = Join-Path $output 'container-ownership.json' +if (-not (Test-Path $ownershipPath)) { + Write-Output 'No owned container was registered; no container deletion is authorized.' + return +} +$ownership = Get-Content $ownershipPath -Raw | ConvertFrom-Json +if ($ownership.runId -ne $env:GITHUB_RUN_ID -or $ownership.arm -ne $env:BC_SQL_PILOT_ARM -or + $env:BC_SQL_API_EXPERIMENT -ne 'control' -or $ownership.experiment -ne $env:BC_SQL_API_EXPERIMENT -or + $env:BC_SQL_PILOT_COUNTRY -notin @('W1', 'DE') -or $env:BC_SQL_PILOT_TRIAL -notmatch '^[1-5]$' -or + $ownership.country -ne $env:BC_SQL_PILOT_COUNTRY -or $ownership.trial -ne $env:BC_SQL_PILOT_TRIAL -or + $ownership.container -ne "bcbuildprojectsTestApps$($env:BC_SQL_PILOT_COUNTRY)Uptake$($env:BC_SQL_PILOT_TRIAL)$($env:BC_SQL_API_EXPERIMENT)$($env:GITHUB_RUN_ID)") { + throw 'Cleanup ownership mismatch.' +} +Import-Module (Join-Path (Split-Path $env:BcContainerHelperPath -Parent) 'BcContainerHelper.psm1') -ErrorAction Stop +try { + if (Test-BcContainer -containerName $ownership.container) { + $events = Get-BcContainerEventLog -containerName $ownership.container -doNotOpen + Copy-Item $events (Join-Path $output 'final-container.evtx') + } + $project = Join-Path $env:GITHUB_WORKSPACE "build\projects\Test Apps $($env:BC_SQL_PILOT_COUNTRY) Uptake$($env:BC_SQL_PILOT_TRIAL)$($env:BC_SQL_API_EXPERIMENT)" + $resultLocations = @{ + 'project-root' = $project + 'buildartifacts' = Join-Path $project '.buildartifacts' + } + foreach ($label in $resultLocations.Keys) { + if (Test-Path $resultLocations[$label]) { + $destination = Join-Path $output "clean-results\$label" + New-Item -ItemType Directory -Path $destination -Force | Out-Null + Get-ChildItem $resultLocations[$label] -Filter 'TestResults*.xml' -File | + Copy-Item -Destination $destination + } + } +} finally { + if (Test-BcContainer -containerName $ownership.container) { + Remove-BcContainer -containerName $ownership.container + } + @{ completedUtc = [DateTime]::UtcNow.ToString('o'); containerRemaining = (Test-BcContainer -containerName $ownership.container) } | + ConvertTo-Json | Set-Content (Join-Path $output 'cleanup.json') -Encoding UTF8 +} +if (Test-BcContainer -containerName $ownership.container) { throw 'Owned container teardown did not complete.' } diff --git a/build/scripts/SqlResetPilot/Lifecycle.Tests.ps1 b/build/scripts/SqlResetPilot/Lifecycle.Tests.ps1 new file mode 100644 index 00000000000..caff235310a --- /dev/null +++ b/build/scripts/SqlResetPilot/Lifecycle.Tests.ps1 @@ -0,0 +1,77 @@ +Import-Module (Join-Path $PSScriptRoot 'Lifecycle.psm1') -Force +function global:Invoke-ScriptInBcContainer { + param($containerName, $useSession, $scriptblock, $argumentList) + throw 'No live container calls are permitted in unit tests.' +} + +Describe 'SQL reset pilot ownership and mapping' { + BeforeEach { + $script:tenants = @('default','tenant2','tenant3','tenant4') | ForEach-Object { + [PSCustomObject]@{ Id = $_; DatabaseName = $_ } + } + Initialize-SqlResetPilot 'owned' $script:tenants 'fresh' '123456789' $PSScriptRoot + } + It 'uses a fresh database target and updates the original caller mapping for the next cycle' { + $first = Get-SqlResetPlan 'owned' 'tenant2' 'tenant2' 'default' + $first.Destination | Should -Be 'tenant2_r123456789_g1' + Complete-SqlResetPlan $first + $script:tenants[1].DatabaseName | Should -Be $first.Destination + $second = Get-SqlResetPlan 'owned' 'tenant2' $script:tenants[1].DatabaseName 'default-test-template' + $second.Previous | Should -Be $first.Destination + $second.Destination | Should -Be 'tenant2_r123456789_g2' + } + It 'retains the original SQL target in control while increasing its observation label' { + Initialize-SqlResetPilot 'owned' $script:tenants 'control' '123456789' $PSScriptRoot + $first = Get-SqlResetPlan 'owned' 'tenant3' 'tenant3' 'default-test-template' + Complete-SqlResetPlan $first + $second = Get-SqlResetPlan 'owned' 'tenant3' 'tenant3' 'default-test-template' + $second.Destination | Should -Be 'tenant3' + $second.Generation | Should -Be 2 + } + It 'rejects stale mappings after a successful rename' { + Complete-SqlResetPlan (Get-SqlResetPlan 'owned' 'tenant2' 'tenant2' 'default') + { Get-SqlResetPlan 'owned' 'tenant2' 'tenant2' 'default' } | Should -Throw + } + It 'never accepts the primary or template as a deletion target' { + { Get-SqlResetPlan 'owned' 'default' 'default' 'default-test-template' } | Should -Throw + { Get-SqlResetPlan 'owned' 'tenant2' 'default-test-template' 'default' } | Should -Throw + { Get-SqlResetPlan 'owned' 'tenant2' 'app' 'default' } | Should -Throw + } + It 'rejects unowned containers, workers and source databases' { + { Get-SqlResetPlan 'shared' 'tenant2' 'tenant2' 'default' } | Should -Throw + { Get-SqlResetPlan 'owned' 'tenant5' 'tenant5' 'default' } | Should -Throw + { Get-SqlResetPlan 'owned' 'tenant2' 'tenant2' 'shared' } | Should -Throw + } + It 'rejects unsafe run identities and unexpected original mappings' { + { Initialize-SqlResetPilot 'owned' $script:tenants 'fresh' '1;drop' $PSScriptRoot } | Should -Throw + $script:tenants[1].DatabaseName = 'default' + { Initialize-SqlResetPilot 'owned' $script:tenants 'fresh' '123' $PSScriptRoot } | Should -Throw + } + It 'preserves the seven original three-worker batches and stops after the target batch' { + $ids = @(139700,139702,139703,139706,139725,139726,139732,139739,139742,139745,139802,139803,139806,139826,139832,139854,139972,139780,148315,148318,148343,148344) + $items = @($ids | ForEach-Object { [PSCustomObject]@{ CodeunitId = $_ } }) + $prefix = @(Select-SqlPilotPrefix $items) + $prefix.Count | Should -Be 21 + $prefix[18].CodeunitId | Should -Be 148315 + $prefix[20].CodeunitId | Should -Be 148343 + $items[0].CodeunitId = 1 + { Select-SqlPilotPrefix $items } | Should -Throw + } + It 'advances mapping only after the container operation succeeds' { + Mock Invoke-ScriptInBcContainer -ModuleName Lifecycle { @{ state = 'Operational' } } + Mock Add-Content -ModuleName Lifecycle {} + Invoke-SqlPilotReset 'owned' 'tenant2' 'tenant2' 'default' + $script:tenants[1].DatabaseName | Should -Be 'tenant2_r123456789_g1' + Should -Invoke Invoke-ScriptInBcContainer -ModuleName Lifecycle -Times 1 -Exactly -Scope It -ParameterFilter { + $containerName -eq 'owned' -and $argumentList.Previous -eq 'tenant2' -and + $argumentList.Destination -eq 'tenant2_r123456789_g1' + } + } + It 'leaves mapping unchanged and propagates a failed restore without retrying' { + Mock Invoke-ScriptInBcContainer -ModuleName Lifecycle { throw 'copy failed' } + Mock Add-Content -ModuleName Lifecycle {} + { Invoke-SqlPilotReset 'owned' 'tenant2' 'tenant2' 'default' } | Should -Throw + $script:tenants[1].DatabaseName | Should -Be 'tenant2' + Should -Invoke Invoke-ScriptInBcContainer -ModuleName Lifecycle -Times 1 -Exactly -Scope It + } +} diff --git a/build/scripts/SqlResetPilot/Lifecycle.psm1 b/build/scripts/SqlResetPilot/Lifecycle.psm1 new file mode 100644 index 00000000000..0acbc839510 --- /dev/null +++ b/build/scripts/SqlResetPilot/Lifecycle.psm1 @@ -0,0 +1,201 @@ +Set-StrictMode -Version 2 +$script:pilot = $null + +function Initialize-SqlResetPilot { + param([string]$ContainerName, [array]$TenantInfo, [string]$Arm, [string]$RunId, [string]$OutputDirectory) + if ($Arm -notin @('control', 'fresh') -or $RunId -notmatch '^\d{1,20}$') { throw 'Invalid pilot identity.' } + if ($TenantInfo.Count -ne 4 -or @($TenantInfo.Id | Sort-Object -Unique).Count -ne 4) { + throw 'Pilot requires exactly default and three distinct workers.' + } + $workers = @{} + foreach ($id in @('tenant2', 'tenant3', 'tenant4')) { + $info = @($TenantInfo | Where-Object Id -eq $id) + if ($info.Count -ne 1 -or $info[0].DatabaseName -ne $id) { throw 'Unexpected initial owned worker mapping.' } + $workers[$id] = @{ Info = $info[0]; Generation = 0; Owned = @($id); Used = @($id) } + } + $source = @($TenantInfo | Where-Object Id -eq 'default') + if ($source.Count -ne 1 -or $source[0].DatabaseName -ne 'default') { throw 'Unexpected protected source mapping.' } + $script:pilot = @{ + Container = $ContainerName; Arm = $Arm; RunId = $RunId; Workers = $workers + OutputDirectory = $OutputDirectory + } +} + +function Get-SqlResetPlan { + param([string]$ContainerName, [string]$Tenant, [string]$DatabaseName, [string]$TemplateDatabaseName) + if (-not $script:pilot -or $ContainerName -ne $script:pilot.Container -or + -not $script:pilot.Workers.ContainsKey($Tenant)) { throw 'Unowned container or tenant.' } + $worker = $script:pilot.Workers[$Tenant] + if ($DatabaseName -ne $worker.Info.DatabaseName -or $DatabaseName -notin $worker.Owned -or + $TemplateDatabaseName -notin @('default', 'default-test-template') -or + $DatabaseName -in @('default', 'default-test-template', 'app') -or + $DatabaseName -eq $TemplateDatabaseName) { throw 'Unsafe or stale database mapping.' } + $generation = $worker.Generation + 1 + $destination = if ($script:pilot.Arm -eq 'fresh') { "${Tenant}_r$($script:pilot.RunId)_g$generation" } else { $DatabaseName } + if ($destination -notmatch '^tenant[234](?:_r\d{1,20}_g\d+)?$' -or $destination.Length -gt 64 -or + ($script:pilot.Arm -eq 'fresh' -and $destination -in $worker.Used)) { throw 'Unsafe or reused destination.' } + [PSCustomObject]@{ + Tenant = $Tenant; Previous = $DatabaseName; Destination = $destination + Template = $TemplateDatabaseName; Generation = $generation + } +} + +function Complete-SqlResetPlan { + param($Plan) + $worker = $script:pilot.Workers[$Plan.Tenant] + $worker.Info.DatabaseName = $Plan.Destination + $worker.Generation = $Plan.Generation + $worker.Owned = @($worker.Owned | Where-Object { $_ -ne $Plan.Previous }) + @($Plan.Destination) + $worker.Used += $Plan.Destination +} + +function Invoke-SqlPilotReset { + param([string]$ContainerName, [string]$Tenant, [string]$DatabaseName, [string]$TemplateDatabaseName) + $plan = Get-SqlResetPlan $ContainerName $Tenant $DatabaseName $TemplateDatabaseName + $trace = Join-Path $script:pilot.OutputDirectory 'reset-timeline.jsonl' + @{ phase = 'reset-start'; utc = [DateTime]::UtcNow.ToString('o'); arm = $script:pilot.Arm; plan = $plan } | + ConvertTo-Json -Depth 5 -Compress | Add-Content $trace + try { + $result = Invoke-ScriptInBcContainer -containerName $ContainerName -useSession $false -scriptblock { + param($plan) + $ErrorActionPreference = 'Stop' + $stopwatch = [Diagnostics.Stopwatch]::StartNew() + $mounted = Get-NAVTenant -ServerInstance $ServerInstance -Tenant $plan.Tenant + $localServers = @('.', 'localhost', $env:COMPUTERNAME, '.\SQLEXPRESS', 'localhost\SQLEXPRESS', "$env:COMPUTERNAME\SQLEXPRESS") + if ($mounted.DatabaseName -ne $plan.Previous -or $mounted.DatabaseServer -notin $localServers) { + throw 'Actual mounted mapping differs from the owned local SQL mapping.' + } + if ($plan.Destination -ne $plan.Previous -and (Test-NAVDatabase -DatabaseName $plan.Destination)) { + throw 'Fresh database destination already exists; refusing to overwrite it.' + } + function Read-PilotIdentity($name) { + $connection = New-Object System.Data.SqlClient.SqlConnection 'Server=.\SQLEXPRESS;Database=master;Integrated Security=True;TrustServerCertificate=True' + try { + $connection.Open() + $command = $connection.CreateCommand() + $command.CommandText = 'SELECT name, database_id, create_date, service_broker_guid FROM sys.databases WHERE name = @name' + $null = $command.Parameters.AddWithValue('@name', $name) + $reader = $command.ExecuteReader() + if (-not $reader.Read()) { throw 'Owned SQL database identity is missing.' } + @{ name = [string]$reader[0]; databaseId = [int]$reader[1]; created = [string]$reader[2]; serviceBrokerGuid = [string]$reader[3] } + } finally { $connection.Dispose() } + } + $before = Read-PilotIdentity $plan.Previous + $started = [DateTime]::UtcNow.ToString('o') + Dismount-NAVTenant -ServerInstance $ServerInstance -Tenant $plan.Tenant -Force | Out-Null + if (Test-NAVDatabase -DatabaseName $plan.Previous) { + Remove-NAVDatabase -DatabaseName $plan.Previous | Out-Null + } + Copy-NAVDatabase -SourceDatabaseName $plan.Template -DestinationDatabaseName $plan.Destination -DatabaseServer '.' | Out-Null + Mount-NAVTenant -ServerInstance $ServerInstance -Id $plan.Tenant -DatabaseServer '.' ` + -DatabaseName $plan.Destination -OverwriteTenantIdInDatabase -Force | Out-Null + while ((Get-NAVTenant -ServerInstance $ServerInstance -Tenant $plan.Tenant).State -eq 'Mounting') { + if ($stopwatch.Elapsed.TotalSeconds -ge 300) { throw 'Tenant mount exceeded baseline 300-second bound.' } + Start-Sleep -Milliseconds 250 + } + $mounted = Get-NAVTenant -ServerInstance $ServerInstance -Tenant $plan.Tenant + if ($mounted.State -notin @('Operational', 'OperationalWithWarnings') -or $mounted.DatabaseName -ne $plan.Destination) { + throw 'Mounted state or mapping differs from the expected new generation.' + } + @{ + startedUtc = $started; completedUtc = [DateTime]::UtcNow.ToString('o') + before = $before; after = (Read-PilotIdentity $plan.Destination) + databaseServer = [string]$mounted.DatabaseServer; state = [string]$mounted.State + detailedState = [string]$mounted.DetailedState; forceRefresh = $false + nst = @(Get-Process 'Microsoft.Dynamics.Nav.Server' | ForEach-Object { + @{ pid = $_.Id; version = $_.FileVersion } + }) + } + } -argumentList $plan + Complete-SqlResetPlan $plan + @{ phase = 'reset-complete'; utc = [DateTime]::UtcNow.ToString('o'); plan = $plan; observation = $result } | + ConvertTo-Json -Depth 8 -Compress | Add-Content $trace + } catch { + # Do not log exception text: SQL/provider diagnostics can contain connection information. + @{ phase = 'reset-failed'; utc = [DateTime]::UtcNow.ToString('o'); plan = $plan; errorType = $_.Exception.GetType().FullName } | + ConvertTo-Json -Depth 5 -Compress | Add-Content $trace + throw + } +} + +function Select-SqlPilotPrefix { + param([array]$WorkItems) + $ids = @(139700,139702,139703,139706,139725,139726,139732,139739,139742,139745,139802,139803,139806,139826,139832,139854,139972,139780,148315,148318,148343) + if ($WorkItems.Count -lt $ids.Count) { throw 'Discovery returned an incomplete pilot prefix.' } + for ($i = 0; $i -lt $ids.Count; $i++) { + if ([int]$WorkItems[$i].CodeunitId -ne $ids[$i]) { throw "Original W1 discovery order differs at position $i." } + } + @($WorkItems | Select-Object -First $ids.Count) +} + +<# +.SYNOPSIS + Makes one authenticated companies request from the host after an owned worker restore. +.DESCRIPTION + Uses the disposable container's existing password credential and private API endpoint. + No retries, redirects, response bodies, passwords or authorization headers are logged. +#> +function Invoke-SqlPilotCompaniesProbe { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingAllowUnencryptedAuthentication', '', + Justification = 'Preserves the existing disposable-container Basic authentication over its private Docker address.')] + [CmdletBinding()] + param( + [string]$ContainerName, [string]$Tenant, + [Parameter(Mandatory)][PSCredential]$Credential, + [Parameter(Mandatory)][string]$CompanyName + ) + if (-not $script:pilot -or $ContainerName -ne $script:pilot.Container -or + -not $script:pilot.Workers.ContainsKey($Tenant) -or + $script:pilot.Workers[$Tenant].Generation -lt 1) { + throw 'Companies probe requires an owned, freshly restored worker.' + } + $trace = Join-Path $script:pilot.OutputDirectory 'companies-probes.jsonl' + $observation = @{ + tenant = $Tenant; generation = $script:pilot.Workers[$Tenant].Generation + startedUtc = [DateTime]::UtcNow.ToString('o'); status = $null; passed = $false + clientRequestId = [guid]::NewGuid().ToString(); serverRequestId = $null + uri = $null; retries = 0 + } + $clock = [Diagnostics.Stopwatch]::StartNew() + try { + # Match BCH's direct container API address, without its request wrapper or auth negotiation. + $config = Get-BcContainerServerConfiguration -ContainerName $ContainerName + $ip = Get-BcContainerIpAddress -containerName $ContainerName + $parsedIp = $null + if (-not [Net.IPAddress]::TryParse($ip, [ref]$parsedIp) -or + $config.ServerInstance -notmatch '^[a-zA-Z0-9_-]+$' -or + $config.ClientServicesCredentialType -notin @('NavUserPassword', 'UserPassword')) { + throw 'Unexpected container API configuration.' + } + $scheme = if ($config.ODataServicesSSLEnabled -eq 'true') { 'https' } else { 'http' } + $uri = [UriBuilder]::new($scheme, $ip, [int]$config.ODataServicesPort, + "$($config.ServerInstance)/api/v2.0/companies", "?tenant=$Tenant").Uri.AbsoluteUri + $observation.uri = $uri + $response = Invoke-WebRequest -Uri $uri -Method Get -Authentication Basic -Credential $Credential ` + -AllowUnencryptedAuthentication -SkipCertificateCheck -SkipHttpErrorCheck -MaximumRedirection 0 ` + -MaximumRetryCount 0 -TimeoutSec 60 -ErrorAction Stop ` + -Headers @{ Accept = 'application/json'; 'client-request-id' = $observation.clientRequestId } + $observation.status = [int]$response.StatusCode + foreach ($key in @('request-id', 'x-ms-request-id')) { + $value = [string]($response.Headers[$key] | Select-Object -First 1) + if ($value -match '^[a-zA-Z0-9._:-]{1,128}$') { $observation.serverRequestId = $value; break } + } + if ($response.StatusCode -ne 200) { throw 'Companies probe returned non-200 status.' } + $body = $response.Content | ConvertFrom-Json -ErrorAction Stop + if (-not $body.PSObject.Properties['value'] -or + @($body.value | Where-Object { $_.name -eq $CompanyName -and $_.id }).Count -ne 1) { + throw 'Companies probe did not return exactly one expected company.' + } + $observation.passed = $true + } catch { + $observation.errorType = $_.Exception.GetType().FullName + # HTTP exception details can contain authentication material; never emit the original error. + throw "Companies probe failed for $Tenant; see sanitized companies-probes.jsonl. No retry was attempted." + } finally { + $observation.completedUtc = [DateTime]::UtcNow.ToString('o') + $observation.elapsedMilliseconds = $clock.ElapsedMilliseconds + $observation | ConvertTo-Json -Compress | Add-Content $trace + } +} + +Export-ModuleMember -Function Initialize-SqlResetPilot, Get-SqlResetPlan, Complete-SqlResetPlan, Invoke-SqlPilotReset, Select-SqlPilotPrefix, Invoke-SqlPilotCompaniesProbe diff --git a/build/scripts/SqlResetPilot/PlanComparison.ps1 b/build/scripts/SqlResetPilot/PlanComparison.ps1 new file mode 100644 index 00000000000..8ed8f941ee4 --- /dev/null +++ b/build/scripts/SqlResetPilot/PlanComparison.ps1 @@ -0,0 +1,88 @@ +$ErrorActionPreference = 'Stop' +if ($env:GITHUB_REPOSITORY -ne 'microsoft/BCApps' -or + $env:GITHUB_REF -ne 'refs/heads/features/646383-sql-api-300-trial-comparison' -or + $env:GITHUB_EVENT_NAME -ne 'workflow_dispatch' -or $env:GITHUB_RUN_ATTEMPT -ne '1' -or + $env:GITHUB_RUN_ID -notmatch '^\d{1,20}$' -or $env:GITHUB_SHA -notmatch '^[0-9a-f]{40}$') { + throw 'Comparison planning is restricted to the exact manual diagnostic branch, attempt one.' +} +Import-Module (Join-Path $PSScriptRoot 'Comparison.psm1') -Force +function Read-GitHubJson([string]$Path) { + $text = & gh api $Path + if ($LASTEXITCODE -ne 0) { throw "GitHub metadata unavailable for $Path; refusing to schedule." } + $text | ConvertFrom-Json +} +$cells = @(Get-SqlComparisonCell -Mode $env:COMPARISON_MODE -Arm $env:REPLACEMENT_ARM ` + -Country $env:REPLACEMENT_COUNTRY -Trial $env:REPLACEMENT_TRIAL) +$replacement = $null +$directory = Join-Path $env:GITHUB_WORKSPACE '.sql-api-comparison-plan' +$null = New-Item -ItemType Directory -Path $directory -Force +if ($env:COMPARISON_MODE -eq 'replacement') { + if ($env:ORIGINAL_RUN -notmatch '^\d{1,20}$' -or $env:ORIGINAL_JOB -notmatch '^\d{1,20}$') { + throw 'Replacement requires explicit original run and job IDs.' + } + $run = Read-GitHubJson "repos/microsoft/BCApps/actions/runs/$env:ORIGINAL_RUN" + $job = Read-GitHubJson "repos/microsoft/BCApps/actions/jobs/$env:ORIGINAL_JOB" + if ($job.check_run_url -notmatch '^https://api\.github\.com/repos/microsoft/BCApps/check-runs/(\d+)$') { + throw 'Unexpected check-run URL.' + } + $annotations = @(Read-GitHubJson "repos/microsoft/BCApps/check-runs/$($Matches[1])/annotations?per_page=100") + $replacement = Assert-SqlComparisonReplacement -Run $run -Job $job -Annotations $annotations ` + -Cell $cells[0] -ExpectedSha $env:GITHUB_SHA +} elseif ($env:ORIGINAL_RUN -or $env:ORIGINAL_JOB) { + throw 'Original schedule cannot specify previous runs or jobs.' +} +$proof = @() +if ($replacement) { + $artifacts = Read-GitHubJson "repos/microsoft/BCApps/actions/runs/$env:ORIGINAL_RUN/artifacts?per_page=100&name=sql-api-comparison-packages-$($env:REPLACEMENT_COUNTRY)-$env:ORIGINAL_RUN" + $snapshot = @($artifacts.artifacts) + if ($snapshot.Count -ne 1) { throw 'Expected exactly one original comparison country snapshot.' } + $proof = @(Save-SqlComparisonSnapshot -ArtifactId $snapshot[0].id -RunId $env:ORIGINAL_RUN ` + -HeadSha $env:GITHUB_SHA -Country $env:REPLACEMENT_COUNTRY -Directory (Join-Path $directory $env:REPLACEMENT_COUNTRY)) + "w1Package=$(if ($env:REPLACEMENT_COUNTRY -eq 'W1') { $snapshot[0].id } else { '0' })" | Add-Content $env:GITHUB_OUTPUT + "dePackage=$(if ($env:REPLACEMENT_COUNTRY -eq 'DE') { $snapshot[0].id } else { '0' })" | Add-Content $env:GITHUB_OUTPUT + "packageRun=$env:ORIGINAL_RUN" | Add-Content $env:GITHUB_OUTPUT +} else { + if (-not $env:GH_TOKEN) { throw 'Actions credential is required to preserve immutable source archives.' } + $headers = @{ Authorization = "Bearer $env:GH_TOKEN"; Accept = 'application/vnd.github+json' } + foreach ($pin in Get-SqlComparisonArtifact) { + $metadata = Read-GitHubJson "repos/microsoft/BCApps/actions/artifacts/$($pin.id)" + if ($metadata.expired -or $metadata.workflow_run.id -ne 37372848860 -or + $metadata.workflow_run.head_sha -ne 'c4953dceffe02a017adad34973e1955017bf5d20' -or + $metadata.digest -ne "sha256:$($pin.digest)") { + throw "Pinned artifact $($pin.id) is expired or differs; no fallback permitted." + } + $destination = Join-Path $directory $pin.country + $null = New-Item -ItemType Directory -Path $destination -Force + $zip = Join-Path $destination "$($pin.id).zip" + Invoke-WebRequest "https://api.github.com/repos/microsoft/BCApps/actions/artifacts/$($pin.id)/zip" ` + -Headers $headers -OutFile $zip -UseBasicParsing + if ((Get-FileHash $zip -Algorithm SHA256).Hash -ne $pin.digest) { throw 'Source archive hash mismatch.' } + $proof += @{ pin = $pin; metadata = $metadata; verifiedUtc = [datetime]::UtcNow.ToString('o') } + } + foreach ($country in @('W1', 'DE')) { + $countryProof = @($proof | Where-Object { $_.pin.country -eq $country }) + ConvertTo-Json -InputObject $countryProof -Depth 12 | + Set-Content (Join-Path $directory "$country\artifact-proof.json") -Encoding utf8 + $null = Assert-SqlComparisonSnapshot -Directory (Join-Path $directory $country) -Country $country + } + "packageRun=$env:GITHUB_RUN_ID" | Add-Content $env:GITHUB_OUTPUT +} +$manifest = @{ + run = $env:GITHUB_RUN_ID; head = $env:GITHUB_SHA; mode = $env:COMPARISON_MODE + createdUtc = [datetime]::UtcNow.ToString('o'); originalCellCount = $(if ($replacement) { 0 } else { $cells.Count }) + replacementOf = $replacement; cells = $cells; globalContainerLimit = 6 + packagePolicy = 'Original ZIP bytes and source metadata preserved in immutable 14-day country snapshots; SHA256 verified on every download. No rebuild or package substitution.' + batchCount = $(if ($replacement) { 1 } else { 10 }); cellsPerOriginalBatch = 30 + expectedCompleteCohort = @{ codeunits = 21; cases = 253; skipped = 19; addedExclusions = 0 } + outcomePolicy = 'Original first-attempt failures, retries, final failures and communication-invalid jobs remain distinct; never count skipped/cancelled/incomplete jobs as passes.' +} +$manifest | ConvertTo-Json -Depth 12 | Set-Content (Join-Path $directory 'matrix-manifest.json') -Encoding utf8 +ConvertTo-Json -InputObject @($proof) -Depth 12 | Set-Content (Join-Path $directory 'artifact-proof.json') -Encoding utf8 +"mode=$env:COMPARISON_MODE" | Add-Content $env:GITHUB_OUTPUT +"replacement=$(ConvertTo-Json -InputObject $replacement -Depth 8 -Compress)" | Add-Content $env:GITHUB_OUTPUT +foreach ($batch in 1..10) { + $selected = @($cells | Select-Object -Skip (($batch - 1) * 30) -First 30) + $matrix = @{ include = $selected } | ConvertTo-Json -Depth 6 -Compress + "batch$($batch.ToString('00'))=$matrix" | Add-Content $env:GITHUB_OUTPUT +} +Write-Output "Validated $($cells.Count) distinct scheduled cells; global container limit six. No automatic communication replacements." diff --git a/build/scripts/SqlResetPilot/PlanPlatformUptake.ps1 b/build/scripts/SqlResetPilot/PlanPlatformUptake.ps1 new file mode 100644 index 00000000000..b25f6f377bd --- /dev/null +++ b/build/scripts/SqlResetPilot/PlanPlatformUptake.ps1 @@ -0,0 +1,30 @@ +$ErrorActionPreference = 'Stop' +Import-Module (Join-Path $PSScriptRoot 'PlatformUptake.psm1') -Force +Assert-SqlPlatformUptakeContext +$pin = Get-SqlPlatformUptake +git merge-base --is-ancestor $pin.comparisonBase HEAD +if ($LASTEXITCODE -ne 0) { throw 'Original comparison commit must remain an ancestor.' } +git diff --exit-code $pin.applicationSource HEAD -- src +if ($LASTEXITCODE -ne 0) { throw 'Application source differs from compiled PR2.' } +if ((Get-Content (Join-Path $PSScriptRoot '..\..\Packages.json') -Raw | ConvertFrom-Json).BCPlatform.Version -ne $pin.runtime) { + throw 'BCPlatform.Version differs from the published fixed runtime.' +} +$directory = Join-Path $env:GITHUB_WORKSPACE '.sql-api-comparison-plan' +$null = New-Item -ItemType Directory -Path $directory -Force +$proof = @() +foreach ($country in @('W1', 'DE')) { + $proof += @(Save-SqlPlatformUptakeSnapshot -Country $country -Directory (Join-Path $directory $country)) +} +$cells = @(Get-SqlPlatformUptakeCell) +@{ + provenance = $pin; run = $env:GITHUB_RUN_ID; head = $env:GITHUB_SHA + createdUtc = [datetime]::UtcNow.ToString('o'); cells = $cells + originalCellCount = 10; globalContainerLimit = 2; batchCount = 5; cellsPerOriginalBatch = 2 + outcomePolicy = 'Original first attempts only. Incomplete, skipped, cancelled and communication-invalid trials are never passes. No replacements or reruns.' +} | ConvertTo-Json -Depth 15 | Set-Content (Join-Path $directory 'matrix-manifest.json') -Encoding utf8 +ConvertTo-Json -InputObject $proof -Depth 12 | Set-Content (Join-Path $directory 'artifact-proof.json') -Encoding utf8 +foreach ($batch in 1..5) { + $matrix = @{ include = @($cells | Select-Object -Skip (($batch - 1) * 2) -First 2) } | ConvertTo-Json -Depth 6 -Compress + "batch$($batch.ToString('00'))=$matrix" | Add-Content $env:GITHUB_OUTPUT +} +Write-Output 'Validated ten original control cells in five sequential W1/DE pairs; maximum two containers.' diff --git a/build/scripts/SqlResetPilot/PlatformUptake.Tests.ps1 b/build/scripts/SqlResetPilot/PlatformUptake.Tests.ps1 new file mode 100644 index 00000000000..eaa65e386ef --- /dev/null +++ b/build/scripts/SqlResetPilot/PlatformUptake.Tests.ps1 @@ -0,0 +1,260 @@ +$discoveryArm = $env:BC_SQL_PILOT_ARM +try { + $env:BC_SQL_PILOT_ARM = 'control' + Import-Module (Join-Path $PSScriptRoot '..\ParallelTestExecution.psm1') -Force +} finally { $env:BC_SQL_PILOT_ARM = $discoveryArm } +BeforeAll { + Import-Module (Join-Path $PSScriptRoot 'PlatformUptake.psm1') -Force + Import-Module (Join-Path $PSScriptRoot 'Comparison.psm1') -Force + Import-Module powershell-yaml + $script:root = (Resolve-Path (Join-Path $PSScriptRoot '..\..\..')).Path +} + +Describe 'Fixed-platform canonical manifest and immutable control protocol' { + It 'pins official build resource rather than publisher source' { + $pin = Get-SqlPlatformUptake + $pin.runtime | Should -Be '30.0.56092.0' + $pin.publication.fixCommit | Should -Be '7a4d33b8848c5795474eb6d517724e3ae5043baf' + $pin.publication.officialBuild | Should -Be 2860912 + $pin.publication.actualResourceBuild | Should -Be $pin.publication.officialBuild + $pin.publication.actualResourceVersion | Should -Be $pin.runtime + $pin.publication.publisherRun | Should -Be 2861912 + $pin.publication.publisherSelfSourceIsNotBinaryProvenance | Should -BeTrue + } + It 'preserves all four original application archive pins' { + $pin = Get-SqlPlatformUptake + $pin.applicationArtifacts.Count | Should -Be 4 + foreach ($original in Get-SqlComparisonArtifact) { + $artifact = @($pin.applicationArtifacts | Where-Object id -eq $original.id) + $artifact.Count | Should -Be 1 + $artifact[0].digest | Should -Be $original.digest + $artifact[0].country | Should -Be $original.country + $artifact[0].compiledPackageSetSha256 | Should -Match '^[0-9a-f]{64}$' + } + } + It 'has only ten distinct original control cells and the unchanged cohort' { + $cells = @(Get-SqlPlatformUptakeCell) + $cells.Count | Should -Be 10 + @($cells | Where-Object experiment -ne 'control').Count | Should -Be 0 + @($cells | ForEach-Object { "$($_.country)/$($_.trial)" } | Select-Object -Unique).Count | Should -Be 10 + foreach ($country in @('W1', 'DE')) { + (@($cells | Where-Object country -eq $country).trial -join ',') | Should -Be '1,2,3,4,5' + } + $plan = (Get-SqlPlatformUptake).trialPlan + $plan.codeunits.Count | Should -Be 21 + $plan.cases | Should -Be 253 + $plan.expectedPass | Should -Be 234 + $plan.existingSkip | Should -Be 19 + $plan.mountedTenants | Should -Be 4 + $plan.workers | Should -Be 3 + $plan.retries | Should -Be 0 + $plan.addedSkips | Should -Be 0 + $plan.warmup | Should -BeFalse + $plan.companiesProbe | Should -BeFalse + $plan.readinessWait | Should -BeFalse + } + It 'updates every executable runtime guard, not just Packages.json' { + (Get-Content (Join-Path $script:root 'build\Packages.json') -Raw | ConvertFrom-Json).BCPlatform.Version | Should -Be '30.0.56092.0' + $preflight = Get-Content (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Raw + $preflight | Should -Match ([regex]::Escape('/platform/30.0.56092.0/platform')) + $preflight | Should -Match "platform = '30.0.56092.0'" + $container = Get-Content (Join-Path $script:root 'build\scripts\NewBcContainer.ps1') -Raw + $container | Should -Match ([regex]::Escape("'^30\.0\.56092\.0(?:\s|$)'")) + $container | Should -Match 'runtime-preflight.json' + foreach ($source in @($preflight, $container)) { + $source | Should -Not -Match '55665' + } + } + It 'rejects the old installed NST file version, not just the artifact URL' { + $tokens = $null; $errors = $null + $ast = [Management.Automation.Language.Parser]::ParseFile( + (Join-Path $script:root 'build\scripts\NewBcContainer.ps1'), [ref]$tokens, [ref]$errors) + $guard = $ast.Find({ param($node) + $node -is [Management.Automation.Language.IfStatementAst] -and + $node.Clauses[0].Item1.Extent.Text -like '*runtime.nst*' + }, $true) + $guard | Should -Not -BeNullOrEmpty + $check = [scriptblock]::Create($guard.Extent.Text) + $runtime = @{ nst = @(@{ version = '30.0.56092.0' }) } + { & $check } | Should -Not -Throw + foreach ($version in @('30.0.55665.0', '28.0.56092.0', '30.0.56092.01', '')) { + $runtime = @{ nst = @(@{ version = $version }) } + { & $check } | Should -Throw '*Installed NST*' + } + $runtime = @{ nst = @() } + { & $check } | Should -Throw '*Installed NST*' + } + It 'preserves original source, fixtures, auth, settings and lifecycle byte-for-byte' { + $paths = @('src', 'build/projects', 'build/scripts/ApiTestCredential.psm1', + 'build/scripts/SqlResetPilot/Lifecycle.psm1', 'build/scripts/RunTests.ps1', + 'build/scripts/SqlApiTestRetry.psm1') + $diff = & git -C $script:root diff 0227094059f2f26f3fcb1b7f85a3285c17e78b8e -- @paths + $LASTEXITCODE | Should -Be 0 + $diff | Should -BeNullOrEmpty + } +} + +Describe 'Parsed workflow capacity and no automatic fanout' { + BeforeAll { + $script:workflow = Get-Content (Join-Path $script:root '.github\workflows\CICD.yaml') -Raw | ConvertFrom-Yaml + $script:batch = Get-Content (Join-Path $script:root '.github\workflows\SqlApiComparisonBatch.yaml') -Raw | ConvertFrom-Yaml + } + It 'permits manual authorization only and never ordinary CI' { + @($script:workflow.on.Keys).Count | Should -Be 1 + $script:workflow.on.Contains('workflow_dispatch') | Should -BeTrue + $script:workflow.jobs.Count | Should -Be 6 + foreach ($gate in @($script:workflow.jobs.Plan.if, $script:batch.jobs.Pilot.if)) { + $gate | Should -Match "github.repository == 'microsoft/BCApps'" + $gate | Should -Match "github.event_name == 'workflow_dispatch'" + $gate | Should -Match "github.ref == 'refs/heads/features/653457-sql-platform-fix-uptake'" + $gate | Should -Match 'github.run_attempt == 1' + $gate | Should -Match "inputs.authorization == 'AB653457-fixed-platform-original-control-10'" + } + $pr = Get-Content (Join-Path $script:root '.github\workflows\PullRequestHandler.yaml') -Raw | ConvertFrom-Yaml + $pr.jobs.Initialization.if | Should -Match "github.head_ref != 'features/653457-sql-platform-fix-uptake'" + } + It 'serializes all five pairs with an aggregate maximum of two cells' { + $script:batch.jobs.Pilot.strategy.'max-parallel' | Should -Be 2 + $script:batch.jobs.Pilot.strategy.'fail-fast' | Should -BeFalse + $script:workflow.concurrency.'cancel-in-progress' | Should -BeFalse + $script:workflow.jobs.Batch01.needs | Should -Be 'Plan' + foreach ($index in 2..5) { + $job = $script:workflow.jobs[('Batch{0:00}' -f $index)] + ($job.needs -join ',') | Should -Be ('Plan,Batch{0:00}' -f ($index - 1)) + $job.if | Should -Be "always() && !cancelled() && needs.Plan.result == 'success'" + } + foreach ($index in 1..5) { + $job = $script:workflow.jobs[('Batch{0:00}' -f $index)] + $job.with.matrix | Should -Be ('${{ needs.Plan.outputs.batch' + ('{0:00}' -f $index) + ' }}') + } + } + It 'retains always-run owned cleanup and raw event/result uploads' { + $steps = $script:batch.jobs.Pilot.steps + @($steps | Where-Object { $_.run -like '*Finalize.ps1*' })[0].if | Should -Be 'always()' + $upload = @($steps | Where-Object { $_.uses -like 'actions/upload-artifact@*' })[0] + $upload.if | Should -Be 'always()' + $upload.with.path | Should -Match '\.buildartifacts/\*\*/\*\.evtx' + $upload.with.path | Should -Match 'Uptake' + $script:batch.jobs.Pilot.env.BC_SQL_PILOT_ARM | Should -Be 'control' + } +} + +Describe 'Exact authorized cell context' { + BeforeEach { + $script:saved = @{} + $values = @{ + GITHUB_REPOSITORY = 'microsoft/BCApps'; GITHUB_REF = 'refs/heads/features/653457-sql-platform-fix-uptake' + GITHUB_EVENT_NAME = 'workflow_dispatch'; GITHUB_RUN_ATTEMPT = '1'; GITHUB_RUN_ID = '123' + GITHUB_SHA = ('a' * 40); BC_SQL_UPTAKE_AUTHORIZATION = 'AB653457-fixed-platform-original-control-10' + BC_SQL_PILOT_ARM = 'control'; BC_SQL_API_EXPERIMENT = 'control'; BC_SQL_PILOT_COUNTRY = 'W1'; BC_SQL_PILOT_TRIAL = '1' + } + foreach ($envName in $values.Keys) { + $script:saved[$envName] = [Environment]::GetEnvironmentVariable($envName) + [Environment]::SetEnvironmentVariable($envName, $values[$envName]) + } + } + AfterEach { + foreach ($envName in $script:saved.Keys) { [Environment]::SetEnvironmentVariable($envName, $script:saved[$envName]) } + } + It 'accepts exactly the ten selected cells' { + foreach ($cell in Get-SqlPlatformUptakeCell) { + $env:BC_SQL_PILOT_COUNTRY = $cell.country + $env:BC_SQL_PILOT_TRIAL = [string]$cell.trial + { Assert-SqlPlatformUptakeContext -Cell } | Should -Not -Throw + } + } + It 'runs the planner to emit only five sequential country-pair matrices' { + $oldWorkspace = $env:GITHUB_WORKSPACE; $oldOutput = $env:GITHUB_OUTPUT + try { + $env:GITHUB_WORKSPACE = $TestDrive + $env:GITHUB_OUTPUT = Join-Path $TestDrive 'uptake-planner-output.txt' + if (Test-Path $env:GITHUB_OUTPUT) { Remove-Item $env:GITHUB_OUTPUT } + Mock Import-Module {} + Mock Save-SqlPlatformUptakeSnapshot { @{ country = $Country; verified = $true } } + Mock git { $global:LASTEXITCODE = 0 } + & (Join-Path $PSScriptRoot 'PlanPlatformUptake.ps1') + $outputs = @(Get-Content $env:GITHUB_OUTPUT) + $outputs.Count | Should -Be 5 + foreach ($index in 1..5) { + $parts = $outputs[$index - 1] -split '=', 2 + $parts[0] | Should -Be ('batch{0:00}' -f $index) + $matrix = $parts[1] | ConvertFrom-Json + $matrix.include.Count | Should -Be 2 + ($matrix.include.country -join ',') | Should -Be 'W1,DE' + ($matrix.include.trial -join ',') | Should -Be "$index,$index" + ($matrix.include.experiment -join ',') | Should -Be 'control,control' + } + $manifest = Get-Content (Join-Path $TestDrive '.sql-api-comparison-plan\matrix-manifest.json') -Raw | ConvertFrom-Json + $manifest.originalCellCount | Should -Be 10 + $manifest.globalContainerLimit | Should -Be 2 + $manifest.provenance.publication.actualResourceBuild | Should -Be 2860912 + Should -Invoke Save-SqlPlatformUptakeSnapshot -Times 2 -Exactly + } finally { $env:GITHUB_WORKSPACE = $oldWorkspace; $env:GITHUB_OUTPUT = $oldOutput } + } + InModuleScope ParallelTestExecution { + It 'selects original control with no warmup, companies probe, or SQL retry' { + Test-SqlApiExperiment | Should -BeTrue + Test-SqlApiWarmupEnabled | Should -BeFalse + $state = [PSCustomObject]@{ + jobs = @(); hasFailures = $false; transient = @(); retried = @{}; retryTenant = @{}; sqlRetryEvidence = @{} + } + Register-TestJobOutcome ([PSCustomObject]@{ Outcome = 'SqlPoolRetry' }) $state + $state.hasFailures | Should -BeTrue + $state.transient.Count | Should -Be 0 + Mock Reset-BcTestTenant {} + Mock Invoke-SqlPilotCompaniesProbe { throw 'Probe forbidden.' } + Mock Start-RequiredDisabledDispatch {} + Mock Wait-ForAllTestJobs {} + $parameters = @{ containerName = 'owned'; companyName = 'My Company'; credential = [PSCredential]::Empty } + $item = [PSCustomObject]@{ Key = 'app::148318'; AppName = 'app'; CodeunitId = '148318'; TestCount = 3 } + Invoke-RequiredDisabledTestExecution $parameters @($item) @([PSCustomObject]@{ Id = 'tenant2'; DatabaseName = 'tenant2' }) ` + 'default-test-template' 'runner.ps1' 'IntegrationTest' | Should -BeTrue + Should -Invoke Reset-BcTestTenant -Times 1 -Exactly + Should -Invoke Invoke-SqlPilotCompaniesProbe -Times 0 + Should -Invoke Start-RequiredDisabledDispatch -Times 1 -Exactly + } + It 'fails closed instead of entering legacy warmup for invalid uptake authorization or arm' { + $env:BC_SQL_UPTAKE_AUTHORIZATION = '' + { Test-SqlApiWarmupEnabled } | Should -Throw '*refusing warmup fallback*' + $env:BC_SQL_UPTAKE_AUTHORIZATION = 'AB653457-fixed-platform-original-control-10' + foreach ($arm in @('warmup', 'retry')) { + $env:BC_SQL_API_EXPERIMENT = $arm + Test-SqlApiExperiment | Should -BeFalse + { Test-SqlApiWarmupEnabled } | Should -Throw '*refusing warmup fallback*' + } + } + } + It 'rejects =' -ForEach @( + @{ Key = 'GITHUB_REF'; Value = 'refs/heads/features/646383-sql-api-300-trial-comparison' } + @{ Key = 'GITHUB_EVENT_NAME'; Value = 'pull_request' } + @{ Key = 'GITHUB_RUN_ATTEMPT'; Value = '2' } + @{ Key = 'BC_SQL_UPTAKE_AUTHORIZATION'; Value = '' } + @{ Key = 'GITHUB_REPOSITORY'; Value = 'other/BCApps' } + @{ Key = 'BC_SQL_API_EXPERIMENT'; Value = 'warmup' } + @{ Key = 'BC_SQL_API_EXPERIMENT'; Value = 'retry' } + @{ Key = 'BC_SQL_PILOT_ARM'; Value = 'fresh' } + @{ Key = 'BC_SQL_PILOT_TRIAL'; Value = '6' } + @{ Key = 'BC_SQL_PILOT_TRIAL'; Value = '01' } + @{ Key = 'BC_SQL_PILOT_COUNTRY'; Value = 'US' } + ) { + [Environment]::SetEnvironmentVariable($Key, $Value) + { Assert-SqlPlatformUptakeContext -Cell } | Should -Throw + } +} + +Describe 'Compiled package and transport fail-closed checks' { + It 'rejects changed compiled package hashes or missing packages' { + { Assert-SqlPlatformUptakePackageSet -Country W1 -Kind apps -Files @(@{ name = 'modified.app'; sha256 = ('a' * 64) }) } | Should -Throw + { Assert-SqlPlatformUptakePackageSet -Country DE -Kind tests -Files @() } | Should -Throw + } + It 'rejects a snapshot whose immutable ID has the wrong transport digest before downloading' { + $old = $env:GH_TOKEN + try { + $env:GH_TOKEN = 'synthetic' + Mock Invoke-RestMethod -ModuleName PlatformUptake { @{ id = '11487493885'; digest = 'sha256:wrong' } } + Mock Invoke-WebRequest -ModuleName PlatformUptake { throw 'Download must not occur.' } + { Save-SqlPlatformUptakeSnapshot -Country W1 -Directory $TestDrive } | Should -Throw '*ID/digest differs*' + Should -Invoke Invoke-WebRequest -ModuleName PlatformUptake -Times 0 + } finally { $env:GH_TOKEN = $old } + } +} diff --git a/build/scripts/SqlResetPilot/PlatformUptake.json b/build/scripts/SqlResetPilot/PlatformUptake.json new file mode 100644 index 00000000000..9459164a837 --- /dev/null +++ b/build/scripts/SqlResetPilot/PlatformUptake.json @@ -0,0 +1,88 @@ +{ + "schemaVersion": 1, + "authorization": "AB653457-fixed-platform-original-control-10", + "branch": "features/653457-sql-platform-fix-uptake", + "comparisonBase": "0227094059f2f26f3fcb1b7f85a3285c17e78b8e", + "originalSnapshotRun": "37634358042", + "applicationSource": "c4953dceffe02a017adad34973e1955017bf5d20", + "applicationRun": "37372848860", + "applicationVersion": "30.0.55683.0", + "previousRuntime": "30.0.55665.0", + "runtime": "30.0.56092.0", + "publication": { + "observedUtc": "2026-10-09T11:00:34Z", + "fixPullRequest": "https://microsoft.ghe.com/bic/BC-Platform/pull/47167", + "fixCommit": "7a4d33b8848c5795474eb6d517724e3ae5043baf", + "officialDefinition": 698, + "officialBuild": 2860912, + "officialSource": "3ed6bbc6787b3f832c1ba7d2163a49bfec75f50f", + "commitsAheadOfFix": 1, + "officialResult": "Succeeded", + "publisherDefinition": 2336, + "publisherRun": 2861912, + "publisherResult": "Succeeded", + "actualResource": "_Platform-Core-OfficialBuild", + "actualResourceBuild": 2860912, + "actualResourceVersion": "30.0.56092.0", + "publisherSelfSourceIsNotBinaryProvenance": true, + "index": "https://bcinsider-fvh2ekdjecfjd6gk.b02.azurefd.net/platform/indexes/platform.json", + "creationUtc": "2026-10-09T10:47:20Z" + }, + "snapshots": [ + { + "country": "W1", + "id": "11487493885", + "digest": "09be1c12a5fe014fd2c1e0a6ab075e809f5693a9294dc8aa949c53961d1b50bd" + }, + { + "country": "DE", + "id": "11486874993", + "digest": "786e121028e19304a94fcf86da7d40326701a5a19631adbcaf3302dac9abb5ac" + } + ], + "applicationArtifacts": [ + { + "country": "W1", "kind": "apps", "id": "11374170356", + "digest": "683343673e6efeb7699734b250d2ee5004d2d83fe08e57f324c4c645c09612db", + "compiledPackageCount": 117, + "compiledPackageSetSha256": "e54b977a72f2232cc293e1442740252c1e82f553c9c21da2fa86c9273b4d220b" + }, + { + "country": "W1", "kind": "tests", "id": "11374145359", + "digest": "f75ce06920437328e5d79a5512eddcc2425624bb696c339c108478c83554171d", + "compiledPackageCount": 131, + "compiledPackageSetSha256": "a556c75d78c7becac2050e8068931e279196cc382a7d86846044ac298182e339" + }, + { + "country": "DE", "kind": "apps", "id": "11376415128", + "digest": "409af00bb5e6922224626f94a4d4f5625f4a9bf13b9398e84cc101a41a313dd5", + "compiledPackageCount": 123, + "compiledPackageSetSha256": "0288721b1bfdecc31c13200ef40c3d5205e937b18478e0fc6768e43df82a65f3" + }, + { + "country": "DE", "kind": "tests", "id": "11375174896", + "digest": "4e1edde77089e0b586679b168f11123a8181a99c63c3a82b42323503340a5d3b", + "compiledPackageCount": 131, + "compiledPackageSetSha256": "8074c1c7e2251b573a66914f5e66e9f93a251abeddc747e63812d4c009bcf912" + } + ], + "trialPlan": { + "arm": "control", + "countries": ["W1", "DE"], + "trials": [1, 2, 3, 4, 5], + "cellCount": 10, + "firstPairBeforeRemainingPairs": true, + "globalContainerLimit": 2, + "mountedTenants": 4, + "workers": 3, + "warmup": false, + "companiesProbe": false, + "readinessWait": false, + "retries": 0, + "addedSkips": 0, + "codeunits": [139700,139702,139703,139706,139725,139726,139732,139739,139742,139745,139802,139803,139806,139826,139832,139854,139972,139780,148315,148318,148343], + "cases": 253, + "expectedPass": 234, + "existingSkip": 19 + } +} diff --git a/build/scripts/SqlResetPilot/PlatformUptake.psm1 b/build/scripts/SqlResetPilot/PlatformUptake.psm1 new file mode 100644 index 00000000000..e33fc26e991 --- /dev/null +++ b/build/scripts/SqlResetPilot/PlatformUptake.psm1 @@ -0,0 +1,57 @@ +function Get-SqlPlatformUptake { + Get-Content (Join-Path $PSScriptRoot 'PlatformUptake.json') -Raw | ConvertFrom-Json +} + +function Assert-SqlPlatformUptakeContext { + param([switch]$Cell) + if ($env:GITHUB_REPOSITORY -ne 'microsoft/BCApps' -or + $env:GITHUB_REF -ne 'refs/heads/features/653457-sql-platform-fix-uptake' -or + $env:GITHUB_EVENT_NAME -ne 'workflow_dispatch' -or $env:GITHUB_RUN_ATTEMPT -ne '1' -or + $env:BC_SQL_UPTAKE_AUTHORIZATION -ne 'AB653457-fixed-platform-original-control-10' -or + $env:GITHUB_RUN_ID -notmatch '^\d{1,20}$' -or $env:GITHUB_SHA -notmatch '^[0-9a-f]{40}$') { + throw 'Fixed-platform uptake requires its exact authorized manual branch and attempt one.' + } + if ($Cell -and ($env:BC_SQL_PILOT_ARM -ne 'control' -or $env:BC_SQL_API_EXPERIMENT -ne 'control' -or + $env:BC_SQL_PILOT_COUNTRY -notin @('W1', 'DE') -or $env:BC_SQL_PILOT_TRIAL -notmatch '^[1-5]$')) { + throw 'Fixed-platform uptake permits only the ten original control cells.' + } +} + +function Get-SqlPlatformUptakeCell { + foreach ($trial in 1..5) { + foreach ($country in @('W1', 'DE')) { + [PSCustomObject]@{ experiment = 'control'; country = $country; trial = $trial } + } + } +} + +function Save-SqlPlatformUptakeSnapshot { + param([ValidateSet('W1', 'DE')][string]$Country, [string]$Directory) + $pin = Get-SqlPlatformUptake + $snapshot = @($pin.snapshots | Where-Object country -eq $Country)[0] + if (-not $env:GH_TOKEN) { throw 'Actions credential is required for immutable package transport.' } + $metadata = Invoke-RestMethod "https://api.github.com/repos/microsoft/BCApps/actions/artifacts/$($snapshot.id)" ` + -Headers @{ Authorization = "Bearer $env:GH_TOKEN"; Accept = 'application/vnd.github+json' } + if ($metadata.id -ne $snapshot.id -or $metadata.digest -ne "sha256:$($snapshot.digest)") { + throw 'Original comparison snapshot ID/digest differs from the canonical uptake manifest.' + } + Import-Module (Join-Path $PSScriptRoot 'Comparison.psm1') -Force + Save-SqlComparisonSnapshot -ArtifactId $snapshot.id -RunId $pin.originalSnapshotRun ` + -HeadSha $pin.comparisonBase -Country $Country -Directory $Directory +} + +function Assert-SqlPlatformUptakePackageSet { + param([ValidateSet('W1', 'DE')][string]$Country, [string]$Kind, [array]$Files) + $pin = @((Get-SqlPlatformUptake).applicationArtifacts | Where-Object { $_.country -eq $Country -and $_.kind -eq $Kind }) + $canonical = @($Files | Sort-Object name | ForEach-Object { "$($_.name)=$($_.sha256.ToLowerInvariant())" }) -join "`n" + $sha = [Security.Cryptography.SHA256]::Create() + try { $digest = ([BitConverter]::ToString($sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($canonical)))).Replace('-', '').ToLowerInvariant() } + finally { $sha.Dispose() } + if ($pin.Count -ne 1 -or $Files.Count -ne $pin[0].compiledPackageCount -or + $digest -ne $pin[0].compiledPackageSetSha256) { + throw 'Extracted compiled packages differ from the original control package set.' + } +} + +Export-ModuleMember -Function Get-SqlPlatformUptake, Assert-SqlPlatformUptakeContext, + Get-SqlPlatformUptakeCell, Save-SqlPlatformUptakeSnapshot, Assert-SqlPlatformUptakePackageSet diff --git a/build/scripts/SqlResetPilot/Preflight.Tests.ps1 b/build/scripts/SqlResetPilot/Preflight.Tests.ps1 new file mode 100644 index 00000000000..97061e8e196 --- /dev/null +++ b/build/scripts/SqlResetPilot/Preflight.Tests.ps1 @@ -0,0 +1,110 @@ +BeforeAll { + function global:Test-BcContainer { param($containerName) $null = $containerName; throw 'Live call forbidden.' } + function global:New-BcContainer { param($useGenericImage) $null = $useGenericImage; throw 'Live call forbidden.' } +} +Describe 'Experiment country and trial container ownership' { + BeforeEach { + $script:saved = @{} + foreach ($name in @('GITHUB_REPOSITORY','GITHUB_REF','GITHUB_EVENT_NAME','GITHUB_RUN_ATTEMPT','GITHUB_RUN_ID', + 'BC_SQL_PILOT_ARM','BC_SQL_PILOT_COUNTRY','BC_SQL_PILOT_TRIAL','BC_SQL_PILOT_OUTPUT','BC_SQL_API_EXPERIMENT','Settings', + 'GITHUB_SHA','BC_SQL_UPTAKE_AUTHORIZATION')) { + $script:saved[$name] = [Environment]::GetEnvironmentVariable($name) + } + $env:GITHUB_REPOSITORY = 'microsoft/BCApps' + $env:GITHUB_REF = 'refs/heads/features/653457-sql-platform-fix-uptake' + $env:GITHUB_SHA = 'a' * 40 + $env:BC_SQL_UPTAKE_AUTHORIZATION = 'AB653457-fixed-platform-original-control-10' + $env:BC_SQL_API_EXPERIMENT = 'control' + $env:GITHUB_EVENT_NAME = 'workflow_dispatch' + $env:GITHUB_RUN_ATTEMPT = '1' + $env:GITHUB_RUN_ID = '123' + $env:BC_SQL_PILOT_ARM = 'control' + $env:BC_SQL_PILOT_COUNTRY = 'DE' + $env:BC_SQL_PILOT_TRIAL = '2' + $env:BC_SQL_PILOT_OUTPUT = $TestDrive + $env:Settings = @{ + country = 'DE'; testType = 'IntegrationTest'; numberOfTenantsForTesting = 4 + companyName = 'My Company'; enableCleanTestCodeunitExecution = $true; enableTaskScheduler = $false + } | ConvertTo-Json + $script:parameters = @{ + ContainerName = 'bcbuildprojectsTestAppsDEUptake2control123' + platformArtifactUrl = 'https://bcinsider-fvh2ekdjecfjd6gk.b02.azurefd.net/platform/30.0.56092.0/platform' + } + Mock Get-Module { { '6.1.19-preview2811389' } } -ParameterFilter { $Name -eq 'BcContainerHelper' } + Mock Test-BcContainer { $false } + } + AfterEach { + foreach ($name in $script:saved.Keys) { [Environment]::SetEnvironmentVariable($name, $script:saved[$name]) } + } + It 'pins image and registers the exact country-trial-run container' { + & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters + $record = Get-Content (Join-Path $TestDrive 'container-ownership.json') -Raw | ConvertFrom-Json + $record.country | Should -Be 'DE' + $record.trial | Should -Be '2' + $record.container | Should -Be 'bcbuildprojectsTestAppsDEUptake2control123' + $record.experiment | Should -Be 'control' + $record.platform | Should -Be '30.0.56092.0' + $script:parameters.useGenericImage | Should -Be 'mcr.microsoft.com/businesscentral@sha256:c899d12093ad7bbdbfd08ccc0e6294e0f98c682c7e35db4ecfbca345fb068492' + } + It 'refuses a preexisting container rather than replacing it' { + Mock Test-BcContainer { $true } + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw '*already exists*' + } + It 'rejects original non-trial container names' { + $script:parameters.ContainerName = 'bcbuildprojectsTestAppsDE123' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw + } + It 'rejects another trial or country mapping' { + $env:BC_SQL_PILOT_TRIAL = '3' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw + $env:BC_SQL_PILOT_TRIAL = '2' + $env:BC_SQL_PILOT_COUNTRY = 'W1' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw + } + It 'rejects reruns and fresh-name treatment' { + $env:GITHUB_RUN_ATTEMPT = '2' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw + $env:GITHUB_RUN_ATTEMPT = '1' + $env:BC_SQL_PILOT_ARM = 'fresh' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw + } + It 'rejects effective country drift' { + $settings = $env:Settings | ConvertFrom-Json + $settings.country = 'W1' + $env:Settings = $settings | ConvertTo-Json + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw '*settings differ*' + } + It 'allows trial 5 but never trial 6 even with matching container names' { + $env:BC_SQL_PILOT_TRIAL = '5' + $script:parameters.ContainerName = 'bcbuildprojectsTestAppsDEUptake5control123' + & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters + $env:BC_SQL_PILOT_TRIAL = '6' + $script:parameters.ContainerName = 'bcbuildprojectsTestAppsDEUptake6control123' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw + } + It 'rejects obsolete exclusion arms and other branches or events' { + $env:BC_SQL_API_EXPERIMENT = 'A' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw + $env:BC_SQL_API_EXPERIMENT = 'control' + $env:GITHUB_REF = 'refs/heads/features/646383-sql-api-two-arm-experiment' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw + $env:GITHUB_REF = 'refs/heads/features/653457-sql-platform-fix-uptake' + $env:GITHUB_EVENT_NAME = 'pull_request' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw + } + It 'rejects the old platform, floating platform and missing authorization' { + foreach ($version in @('30.0.55665.0', 'latest', '28.0.56092.0')) { + $script:parameters.platformArtifactUrl = "https://bcinsider-fvh2ekdjecfjd6gk.b02.azurefd.net/platform/$version/platform" + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw '*pinned source platform*' + } + $env:BC_SQL_UPTAKE_AUTHORIZATION = '' + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw '*authorized manual branch*' + } + It 'rejects warmup and retry before any container inspection' { + foreach ($arm in @('warmup', 'retry')) { + $env:BC_SQL_API_EXPERIMENT = $arm + { & (Join-Path $PSScriptRoot 'ContainerPreflight.ps1') -Parameters $script:parameters } | Should -Throw '*ten original control cells*' + } + Should -Invoke Test-BcContainer -Times 0 + } +} diff --git a/build/scripts/SqlResetPilot/Prepare.ps1 b/build/scripts/SqlResetPilot/Prepare.ps1 new file mode 100644 index 00000000000..69ce79c59f9 --- /dev/null +++ b/build/scripts/SqlResetPilot/Prepare.ps1 @@ -0,0 +1,82 @@ +$ErrorActionPreference = 'Stop' +$base = 'c4953dceffe02a017adad34973e1955017bf5d20' +Import-Module (Join-Path $PSScriptRoot 'PlatformUptake.psm1') -Force +Assert-SqlPlatformUptakeContext -Cell +$uptake = Get-SqlPlatformUptake +git merge-base --is-ancestor $base HEAD +if ($LASTEXITCODE -ne 0) { throw 'PR2 base is not an ancestor.' } +git diff --exit-code $base HEAD -- src +if ($LASTEXITCODE -ne 0) { throw 'AL/package source differs from the pinned compiled PR2 source.' } + +$project = "build\projects\Test Apps $($env:BC_SQL_PILOT_COUNTRY)" +$trialProject = "$project Uptake$($env:BC_SQL_PILOT_TRIAL)$($env:BC_SQL_API_EXPERIMENT)" +if (Test-Path $trialProject) { throw 'Trial project must not already exist.' } +# AL-Go derives its container name from the project path. Preserve wrapper depth and country settings. +Copy-Item $project $trialProject -Recurse +"artifact=https://bcinsider-fvh2ekdjecfjd6gk.b02.azurefd.net/sandbox/30.0.55683.0/$($env:BC_SQL_PILOT_COUNTRY.ToLowerInvariant())" | + Add-Content $env:GITHUB_OUTPUT +$output = Join-Path $env:GITHUB_WORKSPACE 'sql-reset-pilot-output' +New-Item -ItemType Directory $output -Force | Out-Null +"BC_SQL_PILOT_OUTPUT=$output" | Add-Content $env:GITHUB_ENV +@{ phase = 'package-preflight'; arm = $env:BC_SQL_PILOT_ARM; run = $env:GITHUB_RUN_ID; utc = [DateTime]::UtcNow.ToString('o') } | + ConvertTo-Json | Set-Content (Join-Path $output 'start.json') -Encoding UTF8 +$expectedSnapshotRun = $uptake.originalSnapshotRun +if ($env:BC_SQL_COMPARISON_REPLACEMENT -and $env:BC_SQL_COMPARISON_REPLACEMENT -ne 'null') { + throw 'No replacement trials are authorized.' +} +$snapshotDirectory = Join-Path $env:GITHUB_WORKSPACE 'sql-api-package-snapshot' +$snapshotProof = @(Save-SqlPlatformUptakeSnapshot -Country $env:BC_SQL_PILOT_COUNTRY -Directory $snapshotDirectory) +$snapshotProof | ConvertTo-Json -Depth 12 | Set-Content (Join-Path $output 'original-artifact-proof.json') +$artifacts = @( + @{ Kind = 'apps'; Id = 11374170356; Digest = '683343673e6efeb7699734b250d2ee5004d2d83fe08e57f324c4c645c09612db' }, + @{ Kind = 'tests'; Id = 11374145359; Digest = 'f75ce06920437328e5d79a5512eddcc2425624bb696c339c108478c83554171d' } +) +if ($env:BC_SQL_PILOT_COUNTRY -eq 'DE') { + $artifacts = @( + @{ Kind = 'apps'; Id = 11376415128; Digest = '409af00bb5e6922224626f94a4d4f5625f4a9bf13b9398e84cc101a41a313dd5' }, + @{ Kind = 'tests'; Id = 11375174896; Digest = '4e1edde77089e0b586679b168f11123a8181a99c63c3a82b42323503340a5d3b' } + ) +} +$manifest = @() +foreach ($artifact in $artifacts) { + $metadata = @($snapshotProof | Where-Object { $_.pin.id -eq [string]$artifact.Id })[0].metadata + if ($metadata.expired -or $metadata.workflow_run.id -ne 37372848860 -or + $metadata.workflow_run.head_sha -ne $base -or $metadata.digest -ne "sha256:$($artifact.Digest)") { + throw 'Exact artifact provenance/digest check failed; no moving-build fallback is permitted.' + } + $destination = Join-Path $env:GITHUB_WORKSPACE "sql-reset-pilot-packages\$($artifact.Kind)" + New-Item -ItemType Directory $destination -Force | Out-Null + $zip = Join-Path $snapshotDirectory "$($artifact.Id).zip" + if ((Get-FileHash $zip -Algorithm SHA256).Hash -ne $artifact.Digest) { throw 'Artifact archive hash mismatch.' } + Expand-Archive $zip $destination + $files = @(Get-ChildItem $destination -Filter '*.app' -Recurse -File | Sort-Object FullName) + if ($files.Count -eq 0) { throw 'Pinned artifact contains no app packages.' } + $list = Join-Path $destination 'packages.json' + ConvertTo-Json -InputObject @($files.FullName) | Set-Content $list -Encoding UTF8 + "$($artifact.Kind)=$list" | Add-Content $env:GITHUB_OUTPUT + $packageFiles = @($files | ForEach-Object { @{ name = $_.Name; sha256 = (Get-FileHash $_.FullName).Hash } }) + Assert-SqlPlatformUptakePackageSet -Country $env:BC_SQL_PILOT_COUNTRY -Kind $artifact.Kind -Files $packageFiles + $manifest += @{ + artifactId = $artifact.Id; sourceRun = 37372848860; sourceHead = $base + kind = $artifact.Kind; archiveSha256 = $artifact.Digest + files = $packageFiles + } +} +@{ + experimentHead = $env:GITHUB_SHA; run = $env:GITHUB_RUN_ID; arm = $env:BC_SQL_PILOT_ARM + experiment = $env:BC_SQL_API_EXPERIMENT; sharedBaseline = 'fbd7ec46c636ee5f9d940cb81e5abbc1df90f055' + probeAndWarmupBaseline = 'fcc1776c6b165199dd66e4227675b1cc31da7a8f' + trialIdentity = "$($env:BC_SQL_API_EXPERIMENT)/$($env:BC_SQL_PILOT_COUNTRY)/$($env:BC_SQL_PILOT_TRIAL)" + platformUptake = $uptake + replacementOf = $null + packageSnapshot = @{ runId = $expectedSnapshotRun; artifactId = @($uptake.snapshots | Where-Object country -eq $env:BC_SQL_PILOT_COUNTRY)[0].id } + country = $env:BC_SQL_PILOT_COUNTRY; trial = $env:BC_SQL_PILOT_TRIAL; project = $trialProject + warmup = $(if ($env:BC_SQL_API_EXPERIMENT -eq 'control') { 'none' } else { 'original-first-app-before-clean-lane' }) + companiesProbe = $(if ($env:BC_SQL_API_EXPERIMENT -eq 'control') { 'none' } else { 'per-restored-worker-single-attempt' }) + companiesProbeMaximumAttempts = 1; companiesProbeTimeoutSeconds = 60; companiesProbeRetryDelaySeconds = 0 + additionalDisabledTests = @() + warmupRetries = 0; maximumEvidenceGatedRetriesPerCodeunit = $(if ($env:BC_SQL_API_EXPERIMENT -eq 'retry') { 1 } else { 0 }) + genericTestRetries = 0; schedulerRetries = 0; ciRetries = 0 + budgetMinutes = 120; startedUtc = [DateTime]::UtcNow.ToString('o') + artifacts = $manifest +} | ConvertTo-Json -Depth 15 | Set-Content (Join-Path $output 'provenance.json') -Encoding UTF8 diff --git a/build/scripts/SqlResetPilot/README.md b/build/scripts/SqlResetPilot/README.md new file mode 100644 index 00000000000..812907ad0f7 --- /dev/null +++ b/build/scripts/SqlResetPilot/README.md @@ -0,0 +1,172 @@ +# Fixed-platform uptake — AB#653457 — DO NOT MERGE + +This isolated branch starts at original comparison commit +`0227094059f2f26f3fcb1b7f85a3285c17e78b8e`, not current main. Its only +runtime treatment is **30.0.55665.0 → 30.0.56092.0**. The platform fix +`7a4d33b8848c5795474eb6d517724e3ae5043baf` is an ancestor of official build +2860912 (definition 698). Publisher 2861912 (definition 2336) consumed that +exact `_Platform-Core-OfficialBuild` resource; its own source is not binary +provenance. CDN publication was verified 2026-10-09T11:00:34Z. + +The new manual `CICD.yaml` requires branch +`features/653457-sql-platform-fix-uptake`, attempt one, and authorization +`AB653457-fixed-platform-original-control-10`. It schedules **ten original +control cells**, W1/DE indices 1–5, in five sequential pairs, each with at +most two containers. Pair one completes before pairs two–five; failures +remain failures and do not suppress later original pairs. No replacements, +reruns, readiness waits, warmups, companies probes, added skips or compilation. +Automatic PR initialization excludes this branch. No ordinary full CI exists +in this branch's manual-only CICD workflow. + +`PlatformUptake.json` is the canonical fixed-build, application archive, +compiled-package-set, snapshot transport and selected-plan provenance. +`PlanPlatformUptake.ps1` validates the original comparison's still-live country +snapshots; it does **not** download expired source artifacts or substitute +newer packages. Every cell repeats the transport, source, ZIP and extracted +package hash checks. Package-set fingerprints are SHA256 of UTF-8, +LF-joined `name=lowercase-sha256` lines sorted by name, without trailing LF. +They were taken from original control W1/DE trial-one provenance. + +The exact 21 CUs/253 methods/234 expected passes/19 existing skips, four +mounted tenants/three workers, password-file authentication, helper, image, +application artifact, company, clean-template lifecycle and failure finalizers +remain the original control protocol below. Installed NST process file version +must match 30.0.56092.0; `runtime-preflight.json` is runtime evidence, not the +publication manifest. Owned names use `Uptakecontrol` and reject +preexisting containers; teardown cannot touch original comparison containers. + +Local unit/static checks are not installed-runtime or SQL-fix verification. +Parent review, capacity/duplicate-run checks and one authorized dispatch remain +necessary. Historical baseline, readiness and tenant20 campaigns are unchanged. + +## Historical original-300 protocol (reference only; not this branch's schedule) + +Explicit user authorization: 2026-10-07. One manual `CICD.yaml` dispatch on +`features/646383-sql-api-300-trial-comparison` with `mode=originals` schedules +**3 arms × W1/DE × 50 indices = 300 original disposable-container trials**. +The separate historical DE replacement `37630750803` is not part of these 300. +No exclusion arm, automatic job rerun, production fix, shared NST, or AL changes. + +## Arms + +| Identity | Pre-clean first-app warmup | One companies probe after each worker restore | Evidence-qualified whole-CU retry | +| --- | --- | --- | --- | +| control | No | No | No | +| warmup | Yes | Yes | No | +| retry | Yes | Yes | At most once per CU | + +All arms use the same discovery, pristine-template freeze, owned worker reset, +21-CU order, four tenants (default plus three workers), ordinary baseline skip +configuration, artifacts and diagnostic instrumentation. The common source is +`fbd7ec46c636ee5f9d940cb81e5abbc1df90f055`, with obsolete method exclusion removed. +`Lifecycle.psm1` and its probe tests are restored exactly from original warmup +`fcc1776c6b165199dd66e4227675b1cc31da7a8f`: **one request, TimeoutSec 60, +MaximumRetryCount 0**, no probe retry. Both warmup arms use that identical code. +The template is frozen before first-app warmup on default. Each three-worker +batch completes all restores (then all probes, when enabled) before test dispatch. +As in the original pilot, terminal failures drain the current batch and stop +later CUs; incomplete trials are never passes. This rule is identical across arms. + +## Scheduling and resource bound + +`PlanComparison.ps1` validates pins and writes the canonical manifest before +any containers start. Ten sequential reusable-workflow batches each contain +30 cells (five indices × two countries × three arms), below the 256 matrix limit. +Each batch has `fail-fast: false`, maximum parallelism **six**, and depends on +completion of the preceding entire batch. Failed trials do not skip subsequent +batches. Queue order rotates arms and countries across balanced six-cell index +blocks; runner placement/execution order is not guaranteed and remains a possible +confound to report. Workflow-level concurrency serializes this comparison and +its explicit replacements; it does not cancel unrelated work. + +Each cell has a 120-minute timeout. Worst-case allocation is 36,000 runner-minutes, +with approximately 100 hours of test execution at the six-container ceiling; +actual queues, setup and trial durations determine elapsed time. The requested +300 are not reduced to fit an EOD target. No guarantee of finishing by tomorrow. + +Exact repository, branch, manual event and `run_attempt == 1` gates protect +planning, execution and provisioning. Automatic PR Initialization excludes this +exact branch. No PR is necessary for dispatch; existing draft PRs remain untouched. + +## Immutable packages and platform + +AL/package source **c4953dceffe02a017adad34973e1955017bf5d20**, source run +**37372848860**. `Prepare.ps1` checks ancestry, no source diff, artifact metadata, +archive SHA256 and per-package hashes. Plan checks and downloads all four original +artifacts while unexpired, then uploads their **unchanged ZIP bytes** and original +metadata into immutable, 14-day W1/DE snapshot artifacts on this run. This avoids +the original artifacts' 2026-10-08 expiry cutting off later bounded batches. +Every cell validates its snapshot's exact run/revision/name, transport digest, +original artifact IDs/source/digests, inner ZIP hashes, and extracted package hashes. +There is no rebuild or package substitution. Explicit replacements reuse the +original comparison's country snapshot, not a newer build. Snapshot expiry/drift +fails closed. Package archive IDs remain those of the original source in provenance; +the separate snapshot artifact/run IDs are additionally recorded. + +| Country | App artifact | Test artifact | +| --- | --- | --- | +| W1 | 11374170356 | 11374145359 | +| DE | 11376415128 | 11375174896 | + +Exact SHA256 pins are recorded in `Comparison.psm1`, `Prepare.ps1`, and uploaded +`artifact-proof.json`. NST **30.0.55665.0**, application **30.0.55683.0**, BCH +**6.1.19-preview2811389**, AL-Go `91b96c2b294be6f823277dafe6f03350abfb9d23`, +generic image `sha256:c899d12093ad7bbdbfd08ccc0e6294e0f98c682c7e35db4ecfbca345fb068492`, +PowerShell 7, existing password-file authentication, and `My Company` are unchanged. + +## Retry evidence and accounting + +Every failed JUnit case must contain the observed GET 500/InternalServerError, +null-reference response, and CorrelationId. Each must match an NST Application +event 701 in that dispatch's UTC window, with the same ClientSessionId, +RootException NullReferenceException, and all three observed stack frames: +`NavSqlConnectionScope.AcquireSqlConnectionFromPool`, +`MetadataProvider.GetRelativeHelpUrl`, `PageDataProvider.GetNavRecordDataAsync`. +Generic HTTP500/NRE, mixed assertions, stale/unmatched events, stopped jobs, +missing/partial XML, or evidence persistence failure never authorize retry. + +All arms retain matching first-attempt evidence, but only `retry` schedules +one whole-CU replay on its freshly restored worker with another single probe. +BCH `ReRun` is removed so all methods run. Recovery requires the exact original +names, count and skip states with no failures/errors. Original and retry result +snapshots remain separate. Only validated recovery replaces that CU in final XML. +Failed retries remain failures and cannot retry again. + +Full completed coverage requires **21 suites, 253 cases, 19 baseline skips**; +the 234 non-skipped cases must pass for an unrecovered first-attempt pass. +`148318.CapabilitiesProjectsEnabledViaAPI` must appear exactly once and remain +enabled in every arm. Never count baseline skips, missing results, cancellations +or communication-invalid trials as passing. Report original SQL failures, +retry recoveries, final failures and infrastructure invalids separately. + +Ordered cohort: +139700,139702,139703,139706,139725,139726,139732,139739,139742,139745, +139802,139803,139806,139826,139832,139854,139972,139780,148315,148318,148343. + +Artifacts are unique by arm/country/index/run and retained 14 days. Always-run +Finalize and upload preserve ownership/cleanup evidence, raw worker logs, EVTX, +nested `.buildartifacts` results, ordered prefix, reset timeline, probe records, +warmup outcomes, per-attempt XML/outcomes and correlated NST events. Per-CU +snapshots can contain earlier suites on that worker: aggregate only their named CU. +Runner loss may prevent final export/cleanup; parent monitoring must audit that, +not interpret absent evidence as success. + +## Explicit communication replacements — not automatically dispatched + +After summarizing original communication failures, invoke the same workflow with +`mode=replacement`, `replacementArm`, `replacementCountry`, `replacementTrial`, +`originalRun`, and `originalJob`. This schedules exactly one cell in Batch01; +Batch02–10 skip. The planner verifies the source run is this comparison's +**originals** run at the exact same SHA, the failed job matches the canonical +identity, and its authoritative failure annotation says the self-hosted runner +lost communication with the server. Genuine test/SQL failures cannot pass this gate. +`replacementOf` retains source run/job/event/attempt/workflow SHA and annotation. +The original stays invalid in original-300 accounting; replacements are separate. +Do not use GitHub's normal rerun button (attempt-two gates intentionally reject it). +Dispatch replacements one at a time: GitHub concurrency permits one pending run +and can supersede an older pending run if multiple are submitted. + +Local validation: focused Pester suites under `SqlResetPilot`, +`tests/SqlApiTestRetry.Test.ps1`, `tests/ParallelTestExecution.Test.ps1`; +PSScriptAnalyzer, parsed YAML dependency/matrix checks and `git diff --check`. +All local container operations are mocked. diff --git a/build/scripts/SqlResetPilot/Snapshot.Tests.ps1 b/build/scripts/SqlResetPilot/Snapshot.Tests.ps1 new file mode 100644 index 00000000000..d038b36d944 --- /dev/null +++ b/build/scripts/SqlResetPilot/Snapshot.Tests.ps1 @@ -0,0 +1,86 @@ +BeforeAll { + Import-Module (Join-Path $PSScriptRoot 'Comparison.psm1') -Force +} + +Describe 'Immutable country package snapshots' { + BeforeEach { + $script:proof = @( + Get-SqlComparisonArtifact | Where-Object country -eq DE | ForEach-Object { + [PSCustomObject]@{ + pin = $_ + metadata = [PSCustomObject]@{ + id = $_.id; expired = $false; digest = "sha256:$($_.digest)" + workflow_run = [PSCustomObject]@{ + id = 37372848860; head_sha = 'c4953dceffe02a017adad34973e1955017bf5d20' + } + } + } + } + ) + $script:directory = Join-Path $TestDrive 'snapshot' + $null = New-Item -ItemType Directory $script:directory -Force + $script:proof | ConvertTo-Json -Depth 8 | Set-Content (Join-Path $script:directory 'artifact-proof.json') + Mock Get-FileHash -ModuleName Comparison { + $pin = Get-SqlComparisonArtifact | Where-Object { $Path -like "*$($_.id).zip" } + [PSCustomObject]@{ Hash = $pin.digest } + } + } + It 'requires both exact ZIP hashes and original unexpired source provenance' { + @(Assert-SqlComparisonSnapshot -Directory $script:directory -Country DE).Count | Should -Be 2 + Should -Invoke Get-FileHash -ModuleName Comparison -Times 2 -Exactly + } + It 'rejects changed ZIP bytes regardless of correct metadata' { + Mock Get-FileHash -ModuleName Comparison { [PSCustomObject]@{ Hash = 'wrong' } } + { Assert-SqlComparisonSnapshot -Directory $script:directory -Country DE } | Should -Throw + } + It 'rejects source drift and incomplete or wrong-country snapshots' { + { Assert-SqlComparisonSnapshot -Directory $script:directory -Country W1 } | Should -Throw + $script:proof[0].metadata.workflow_run.id = 1 + $script:proof | ConvertTo-Json -Depth 8 | Set-Content (Join-Path $script:directory 'artifact-proof.json') + { Assert-SqlComparisonSnapshot -Directory $script:directory -Country DE } | Should -Throw + @($script:proof[1]) | ConvertTo-Json -Depth 8 | Set-Content (Join-Path $script:directory 'artifact-proof.json') + { Assert-SqlComparisonSnapshot -Directory $script:directory -Country DE } | Should -Throw + } + It 'rejects snapshots captured from already-expired original artifacts' { + $script:proof[0].metadata.expired = $true + $script:proof | ConvertTo-Json -Depth 8 | Set-Content (Join-Path $script:directory 'artifact-proof.json') + { Assert-SqlComparisonSnapshot -Directory $script:directory -Country DE } | Should -Throw + } +} + +Describe 'Snapshot download transport and ownership' { + BeforeEach { + $script:oldToken = $env:GH_TOKEN + $env:GH_TOKEN = 'synthetic-test-token' + $script:metadata = [PSCustomObject]@{ + expired = $false; workflow_run = [PSCustomObject]@{ id = 100; head_sha = 'revision' } + name = 'sql-api-comparison-packages-DE-100'; digest = ('sha256:' + ('a' * 64)) + } + Mock Invoke-RestMethod -ModuleName Comparison { $script:metadata } + Mock Invoke-WebRequest -ModuleName Comparison {} + Mock Get-FileHash -ModuleName Comparison { [PSCustomObject]@{ Hash = ('a' * 64) } } + Mock Expand-Archive -ModuleName Comparison {} + Mock Assert-SqlComparisonSnapshot -ModuleName Comparison { 'validated' } + } + AfterEach { $env:GH_TOKEN = $script:oldToken } + It 'validates owned immutable transport before extracting and checking source ZIPs' { + Save-SqlComparisonSnapshot -ArtifactId 200 -RunId 100 -HeadSha revision -Country DE ` + -Directory (Join-Path $TestDrive 'snapshot') | Should -Be 'validated' + Should -Invoke Invoke-WebRequest -ModuleName Comparison -Times 1 -Exactly + Should -Invoke Expand-Archive -ModuleName Comparison -Times 1 -Exactly + Should -Invoke Assert-SqlComparisonSnapshot -ModuleName Comparison -Times 1 -Exactly + } + It 'rejects wrong run, head, name or expired snapshot before download' { + { Save-SqlComparisonSnapshot 200 101 revision DE (Join-Path $TestDrive 'snapshot') } | Should -Throw + { Save-SqlComparisonSnapshot 200 100 different DE (Join-Path $TestDrive 'snapshot') } | Should -Throw + { Save-SqlComparisonSnapshot 200 100 revision W1 (Join-Path $TestDrive 'snapshot') } | Should -Throw + $script:metadata.expired = $true + { Save-SqlComparisonSnapshot 200 100 revision DE (Join-Path $TestDrive 'snapshot') } | Should -Throw + Should -Invoke Invoke-WebRequest -ModuleName Comparison -Times 0 + } + It 'never extracts a corrupt transport archive' { + Mock Get-FileHash -ModuleName Comparison { [PSCustomObject]@{ Hash = 'corrupted' } } + { Save-SqlComparisonSnapshot 200 100 revision DE (Join-Path $TestDrive 'snapshot') } | Should -Throw + Should -Invoke Expand-Archive -ModuleName Comparison -Times 0 + } +} diff --git a/build/scripts/SqlResetPilot/Warmup.Tests.ps1 b/build/scripts/SqlResetPilot/Warmup.Tests.ps1 new file mode 100644 index 00000000000..331f49cd232 --- /dev/null +++ b/build/scripts/SqlResetPilot/Warmup.Tests.ps1 @@ -0,0 +1,169 @@ +$discoveryArm = $env:BC_SQL_PILOT_ARM +try { + $env:BC_SQL_PILOT_ARM = 'control' + Import-Module (Join-Path $PSScriptRoot '..\ParallelTestExecution.psm1') -Force +} finally { + $env:BC_SQL_PILOT_ARM = $discoveryArm +} +BeforeAll { + $script:oldArm = $env:BC_SQL_PILOT_ARM + $script:oldOutput = $env:BC_SQL_PILOT_OUTPUT + $script:oldRun = $env:GITHUB_RUN_ID + $script:oldRunnerTemp = $env:RUNNER_TEMP + $env:BC_SQL_PILOT_ARM = 'control' + $env:BC_SQL_PILOT_OUTPUT = $TestDrive + $env:GITHUB_RUN_ID = '123' + $env:RUNNER_TEMP = $TestDrive + function global:Get-BcContainerAppInfo { + param($containerName, $tenant, [switch]$tenantSpecificProperties) + $null = $containerName, $tenant, $tenantSpecificProperties + throw 'Live container call forbidden.' + } +} +AfterAll { + $env:BC_SQL_PILOT_ARM = $script:oldArm + $env:BC_SQL_PILOT_OUTPUT = $script:oldOutput + $env:GITHUB_RUN_ID = $script:oldRun + $env:RUNNER_TEMP = $script:oldRunnerTemp +} + +Describe 'Diagnostic first-app warmup' { + InModuleScope ParallelTestExecution { + BeforeEach { + $script:parameters = @{ + containerName = 'owned'; tenant = 'default'; companyName = 'My Company' + JUnitResultFileName = (Join-Path $TestDrive 'TestResults.xml') + } + Mock Invoke-WarmupDispatch { @($Pending | Select-Object -Skip 1) } + } + It 'calls the original warmup once on default and keeps results outside prefix coverage' { + Invoke-SqlPilotWarmup -Parameters $script:parameters -AppNames @('First', 'Second') ` + -AppIdByName @{ First = 'id' } -Tenants @('default','tenant2','tenant3','tenant4') ` + -ScriptPath 'runner.ps1' -TestType 'IntegrationTest' -CleanTenantAppNames @('First','Second') + Should -Invoke Invoke-WarmupDispatch -Times 1 -Exactly -ParameterFilter { + $Parameters.tenant -eq 'default' -and $Tenants[0] -eq 'default' -and + $Parameters.JUnitResultFileName -like '*\warmup\TestResults.xml' -and + $State.rerunBudget -eq 0 -and $CleanTenantAppNames -contains 'First' + } + $script:parameters.JUnitResultFileName | Should -Not -Match '\\warmup\\' + } + It 'stops on warmup failure without retrying' { + Mock Invoke-WarmupDispatch { $State.hasFailures = $true; @($Pending | Select-Object -Skip 1) } + { Invoke-SqlPilotWarmup $script:parameters @('First','Second') @{ First = 'id' } ` + @('default','tenant2') 'runner.ps1' 'IntegrationTest' @('First') } | Should -Throw '*warmup failed*' + Should -Invoke Invoke-WarmupDispatch -Times 1 -Exactly + } + It 'stops on any transient queue without retrying' { + Mock Invoke-WarmupDispatch { $State.transient = @('failed'); @($Pending | Select-Object -Skip 1) } + { Invoke-SqlPilotWarmup $script:parameters @('First','Second') @{ First = 'id' } ` + @('default','tenant2') 'runner.ps1' 'IntegrationTest' @('First') } | Should -Throw '*warmup failed*' + Should -Invoke Invoke-WarmupDispatch -Times 1 -Exactly + } + It 'rejects a skipped warmup or a nondefault primary tenant' { + { Invoke-SqlPilotWarmup $script:parameters @('First','Second') @{} ` + @('default','tenant2') 'runner.ps1' 'IntegrationTest' @('First') } | Should -Throw + $script:parameters.tenant = 'tenant2' + { Invoke-SqlPilotWarmup $script:parameters @('First','Second') @{ First = 'id' } ` + @('tenant2','default') 'runner.ps1' 'IntegrationTest' @('First') } | Should -Throw + Should -Invoke Invoke-WarmupDispatch -Times 0 + } + It 'freezes the template before warmup and only then starts the clean lane' { + $script:order = [Collections.Generic.List[string]]::new() + Mock Test-Path { $false } + Mock Set-Content {} + Mock Get-AvailableBcTenantInfo { + @('default','tenant2','tenant3','tenant4') | ForEach-Object { + [PSCustomObject]@{ Id = $_; DatabaseName = $_ } + } + } + Mock Get-BcContainerAppInfo { + [PSCustomObject]@{ IsInstalled = $true; Name = 'First'; AppId = 'id' } + } + Mock Get-ALGoSetting { $true } + Mock Get-AppRerunBudget { 0 } + Mock Get-RequiredDisabledWorkItems { [PSCustomObject]@{ CodeunitId = 139700 } } + Mock Select-SqlPilotPrefix { $WorkItems } + Mock Reset-BcTestTenant { $script:order.Add('discovery-reset') } + Mock New-BcTestTenantTemplate { $script:order.Add('template'); 'default-test-template' } + Mock Invoke-SqlPilotWarmup { $script:order.Add('warmup') } + Mock Invoke-RequiredDisabledTestExecution { $script:order.Add('clean'); $true } + Mock Merge-TenantTestResults {} + Invoke-ParallelTestExecution $script:parameters 'runner.ps1' 'IntegrationTest' @('First','Second') | + Should -BeTrue + ($script:order -join ',') | Should -Be 'discovery-reset,template,warmup,clean' + } + It 'never dispatches clean tests when warmup fails' { + $script:order = [Collections.Generic.List[string]]::new() + Mock Test-Path { $false } + Mock Set-Content {} + Mock Get-AvailableBcTenantInfo { + @('default','tenant2','tenant3','tenant4') | ForEach-Object { + [PSCustomObject]@{ Id = $_; DatabaseName = $_ } + } + } + Mock Get-BcContainerAppInfo { [PSCustomObject]@{ IsInstalled = $true; Name = 'First'; AppId = 'id' } } + Mock Get-ALGoSetting { $true } + Mock Get-AppRerunBudget { 0 } + Mock Get-RequiredDisabledWorkItems { [PSCustomObject]@{ CodeunitId = 139700 } } + Mock Select-SqlPilotPrefix { $WorkItems } + Mock Reset-BcTestTenant {} + Mock New-BcTestTenantTemplate { 'default-test-template' } + Mock Invoke-SqlPilotWarmup { throw 'warmup failed' } + Mock Invoke-RequiredDisabledTestExecution { $true } + { Invoke-ParallelTestExecution $script:parameters 'runner.ps1' 'IntegrationTest' @('First','Second') } | + Should -Throw '*warmup failed*' + Should -Invoke Invoke-RequiredDisabledTestExecution -Times 0 + } + It 'makes failures terminal even if the ordinary rerun budget is positive' { + foreach ($outcome in @('Failed', 'Transient')) { + $state = [PSCustomObject]@{ + hasFailures = $false; transient = @(); rerun = @() + rerunBudget = 2; tenantCount = 4; rerunDone = @{} + } + Register-TestJobOutcome -Result ([PSCustomObject]@{ Outcome = $outcome }) -State $state + $state.hasFailures | Should -BeTrue + $state.transient.Count | Should -Be 0 + $state.rerun.Count | Should -Be 0 + } + } + } +} + +Describe 'Companies probe batch barrier' { + InModuleScope ParallelTestExecution { + BeforeEach { + $script:order = [Collections.Generic.List[string]]::new() + $script:items = @(1..6 | ForEach-Object { [PSCustomObject]@{ Key = "CU$_" } }) + $script:tenants = @('tenant2','tenant3','tenant4') | ForEach-Object { + [PSCustomObject]@{ Id = $_; DatabaseName = $_ } + } + $script:parameters = @{ containerName = 'owned'; companyName = 'My Company'; credential = [PSCredential]::Empty } + Mock Reset-BcTestTenant { $script:order.Add("reset:$Tenant") } + Mock Invoke-SqlPilotCompaniesProbe { $script:order.Add("probe:$Tenant") } + Mock Start-RequiredDisabledDispatch { $script:order.Add("dispatch:$($TenantInfo.Id)") } + Mock Wait-ForAllTestJobs {} + } + It 'probes each fresh worker once after every reset and before any dispatch in each batch' { + Invoke-RequiredDisabledTestExecution $script:parameters $script:items $script:tenants ` + 'default-test-template' 'runner.ps1' 'IntegrationTest' | Should -BeTrue + $batch = 'reset:tenant2,reset:tenant3,reset:tenant4,probe:tenant2,probe:tenant3,probe:tenant4,dispatch:tenant2,dispatch:tenant3,dispatch:tenant4' + ($script:order -join ',') | Should -Be "$batch,$batch" + Should -Invoke Invoke-SqlPilotCompaniesProbe -Times 6 -Exactly + } + It 'stops without dispatch or retry when a probe fails' { + Mock Invoke-SqlPilotCompaniesProbe { throw 'probe failed' } + { Invoke-RequiredDisabledTestExecution $script:parameters $script:items $script:tenants ` + 'default-test-template' 'runner.ps1' 'IntegrationTest' } | Should -Throw '*probe failed*' + Should -Invoke Reset-BcTestTenant -Times 3 -Exactly + Should -Invoke Invoke-SqlPilotCompaniesProbe -Times 1 -Exactly + Should -Invoke Start-RequiredDisabledDispatch -Times 0 + } + It 'does not execute another batch or retry after a failed test batch' { + Mock Wait-ForAllTestJobs { $state.hasFailures = $true } + Invoke-RequiredDisabledTestExecution $script:parameters $script:items $script:tenants ` + 'default-test-template' 'runner.ps1' 'IntegrationTest' | Should -BeFalse + Should -Invoke Start-RequiredDisabledDispatch -Times 3 -Exactly + Should -Invoke Invoke-SqlPilotCompaniesProbe -Times 3 -Exactly + } + } +} diff --git a/build/scripts/tests/SqlApiTestRetry.Test.ps1 b/build/scripts/tests/SqlApiTestRetry.Test.ps1 new file mode 100644 index 00000000000..d1c7f33f53f --- /dev/null +++ b/build/scripts/tests/SqlApiTestRetry.Test.ps1 @@ -0,0 +1,385 @@ +Describe 'SQL API bounded retry evidence and result validation' { + BeforeAll { + Import-Module (Join-Path $PSScriptRoot '..\SqlApiTestRetry.psm1') -Force + $script:createdContainerStub = -not (Get-Command Invoke-ScriptInBcContainer -ListImported -ErrorAction SilentlyContinue) + if ($script:createdContainerStub) { + function global:Invoke-ScriptInBcContainer { + param([string]$containerName, [scriptblock]$scriptblock, [object[]]$argumentList) + $null = $containerName, $scriptblock, $argumentList + throw 'Container execution must be mocked.' + } + } + function New-FailureMessage { + param([string]$CorrelationId = $script:requestId) + "Assert.Fail failed. GET request failed. Response code is 500 (InternalServerError), expected code is 200. Error code: Unknown. Error message: Object reference not set to an instance of an object. CorrelationId: $CorrelationId." + } + function New-CaseXml { + param([string]$Name, [string]$Message, [switch]$Skipped, [string]$Result = 'Pass') + $body = '' + if ($Message) { + $body = '' + $Result = 'Fail' + } + if ($Skipped) { $body += '' } + '' + $body + '' + } + function Write-Suite { + param([string[]]$Cases = $script:originalCases) + '' + + ($Cases -join '') + '' | + Set-Content -LiteralPath $script:context.ResultFiles.JUnitResultFileName -Encoding utf8 + } + function New-NstEvent { + param( + [string]$CorrelationId = $script:requestId, + [datetime]$Time = $script:eventTime, + [string]$Provider = 'MicrosoftDynamicsNavServer$BC', + [string]$EventId = '701', + [string]$Stack = "RootException: NullReferenceException`nat Microsoft.Dynamics.Nav.Runtime.NavSqlConnectionScope.AcquireSqlConnectionFromPool(...)`nat Microsoft.Dynamics.Nav.XmlMetadata.MetadataProvider.GetRelativeHelpUrl(...)`nat Microsoft.Dynamics.Nav.Service.OData.V4.PageDataProvider.GetNavRecordDataAsync(...)" + ) + $text = [System.Security.SecurityElement]::Escape("ClientSessionId: $CorrelationId`n$Stack") + '' + $EventId + '' + $text + '' + } + } + + AfterAll { + if ($script:createdContainerStub) { Remove-Item function:global:Invoke-ScriptInBcContainer } + } + + BeforeEach { + $script:fixtureRoot = Join-Path $PSScriptRoot ('.sql-api-retry-fixture-' + [guid]::NewGuid().ToString('N')) + $null = New-Item -ItemType Directory -Path $script:fixtureRoot + $script:requestId = '11111111-2222-4333-8444-555555555555' + $script:eventTime = [datetime]::UtcNow.AddSeconds(-10) + $script:context = [pscustomobject]@{ + ContainerName = 'synthetic-container' + Tenant = 'synthetic-tenant' + CodeunitId = 70001 + TestCount = 3 + StartedUtc = $script:eventTime.AddSeconds(-10) + ResultFiles = [pscustomobject]@{ JUnitResultFileName = Join-Path $script:fixtureRoot 'results.xml' } + } + $script:expectedTests = @( + [pscustomobject]@{ Name = 'Synthetic API Codeunit.Read Item'; Skipped = $false } + [pscustomobject]@{ Name = 'Synthetic API Codeunit.Read Customer'; Skipped = $false } + [pscustomobject]@{ Name = 'Synthetic API Codeunit.Disabled Case'; Skipped = $true } + ) + $script:originalCases = @( + New-CaseXml -Name $script:expectedTests[0].Name -Message (New-FailureMessage) + New-CaseXml -Name $script:expectedTests[1].Name + New-CaseXml -Name $script:expectedTests[2].Name -Skipped + ) + $script:passingCases = @( + New-CaseXml -Name $script:expectedTests[0].Name + New-CaseXml -Name $script:expectedTests[1].Name + New-CaseXml -Name $script:expectedTests[2].Name -Skipped + ) + Write-Suite + Mock -ModuleName SqlApiTestRetry Write-Host {} + Mock -ModuleName SqlApiTestRetry Invoke-ScriptInBcContainer { throw 'Live container execution is forbidden.' } + } + + AfterEach { + Remove-Item -LiteralPath $script:fixtureRoot -Recurse -Force + } + + Context 'Evidence classification and preservation' { + BeforeEach { + $script:events = @(New-NstEvent) + Mock -ModuleName SqlApiTestRetry Get-SqlApiRetryEvents { $script:events } + } + + It 'recognizes the observed namespaced event and failure attribute shapes without changing results' { + $before = [System.IO.File]::ReadAllBytes($script:context.ResultFiles.JUnitResultFileName) + $evidence = Get-SqlApiTestRetryEvidence -Context $script:context + $evidence | Should -Not -BeNullOrEmpty + $evidence.RequestIds | Should -Be @($script:requestId) + $evidence.Events | Should -Be $script:events + $evidence.TestCases.Name | Should -Be $script:expectedTests.Name + $evidence.TestCases.Skipped | Should -Be @($false, $false, $true) + [Convert]::ToBase64String([System.IO.File]::ReadAllBytes($script:context.ResultFiles.JUnitResultFileName)) | + Should -Be ([Convert]::ToBase64String($before)) + Should -Invoke -ModuleName SqlApiTestRetry Get-SqlApiRetryEvents -Times 1 -Exactly -ParameterFilter { + $ContainerName -eq 'synthetic-container' -and $StartedUtc -eq $script:context.StartedUtc -and + $FinishedUtc -ge $script:eventTime -and $FinishedUtc -le [datetime]::UtcNow + } + Should -Invoke -ModuleName SqlApiTestRetry Invoke-ScriptInBcContainer -Times 0 + } + + It 'persists the first full suite and events before the result file is replaced by the rerun' { + $original = ([xml](Get-Content -LiteralPath $script:context.ResultFiles.JUnitResultFileName -Raw)).testsuites.testsuite.OuterXml + $evidence = Get-SqlApiTestRetryEvidence -Context $script:context + $files = @(Get-ChildItem -LiteralPath (Join-Path $script:fixtureRoot 'SqlApiRetryEvidence') -Filter '*.json') + $files.Count | Should -Be 1 + $savedBeforeRerun = Get-Content -LiteralPath $files[0].FullName -Raw + ($savedBeforeRerun | ConvertFrom-Json).OriginalSuite | Should -Be $original + Write-Suite -Cases $script:passingCases + Test-SqlApiRetryResult -Context $script:context -ExpectedTests $evidence.TestCases | Should -BeTrue + Get-Content -LiteralPath $files[0].FullName -Raw | Should -Be $savedBeforeRerun + $persisted = $savedBeforeRerun | ConvertFrom-Json + $persisted.Events | Should -Be $script:events + $persisted.RequestIds | Should -Be @($script:requestId) + $persisted.Tenant | Should -Be 'synthetic-tenant' + $persisted.CodeunitId | Should -Be 70001 + $persisted.TestCases.Name | Should -Be $script:expectedTests.Name + } + + It 'rejects without querying events' -ForEach @( + @{ Kind = 'generic 500'; Message = 'Assert.Fail failed. GET request failed. Response code is 500 (InternalServerError), expected code is 200.' } + @{ Kind = 'authentication 401'; Message = 'Assert.Fail failed. GET request failed. Response code is 401 (Unauthorized), expected code is 200.' } + @{ Kind = 'real assertion'; Message = 'Assert.AreEqual failed. Expected quantity 5, actual quantity 4.' } + ) { + $script:originalCases[0] = New-CaseXml -Name $script:expectedTests[0].Name -Message $Message + Write-Suite + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + Should -Invoke -ModuleName SqlApiTestRetry Get-SqlApiRetryEvents -Times 0 + Test-Path (Join-Path $script:fixtureRoot 'SqlApiRetryEvidence') | Should -BeFalse + } + + It 'rejects an eligible HTTP failure mixed with a genuine assertion failure' { + $script:originalCases[1] = New-CaseXml -Name $script:expectedTests[1].Name -Message 'Assert.AreEqual failed. Expected true, actual false.' + Write-Suite + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + Should -Invoke -ModuleName SqlApiTestRetry Get-SqlApiRetryEvents -Times 0 + } + + It 'rejects 401 even when the null-reference text and correlation match' { + $message = (New-FailureMessage).Replace('500 (InternalServerError)', '401 (Unauthorized)') + $script:originalCases[0] = New-CaseXml -Name $script:expectedTests[0].Name -Message $message + Write-Suite + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + Should -Invoke -ModuleName SqlApiTestRetry Get-SqlApiRetryEvents -Times 0 + } + + It 'requires matching events for every failed request' { + $secondRequest = '66666666-7777-4888-8999-aaaaaaaaaaaa' + $script:originalCases[1] = New-CaseXml -Name $script:expectedTests[1].Name -Message (New-FailureMessage -CorrelationId $secondRequest) + Write-Suite + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + $script:events += New-NstEvent -CorrelationId $secondRequest + $evidence = Get-SqlApiTestRetryEvidence -Context $script:context + $evidence.RequestIds | Should -Be @($script:requestId, $secondRequest) + $evidence.Events.Count | Should -Be 2 + } + + It 'rejects correlation in the failure message' -ForEach @( + @{ Kind = 'missing'; Correlation = '' } + @{ Kind = 'malformed'; Correlation = 'not-a-guid' } + @{ Kind = 'overlong'; Correlation = '11111111-2222-4333-8444-5555555555556' } + ) { + $script:originalCases[0] = New-CaseXml -Name $script:expectedTests[0].Name -Message (New-FailureMessage -CorrelationId $Correlation) + Write-Suite + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + Should -Invoke -ModuleName SqlApiTestRetry Get-SqlApiRetryEvents -Times 0 + } + + It 'rejects event evidence with ' -ForEach @( + @{ Kind = 'wrong correlation' } + @{ Kind = 'missing correlation' } + @{ Kind = 'stale time' } + @{ Kind = 'future time' } + @{ Kind = 'wrong provider' } + @{ Kind = 'wrong event ID' } + @{ Kind = 'wrong exception' } + @{ Kind = 'wrong pool frame' } + @{ Kind = 'wrong metadata frame' } + @{ Kind = 'wrong OData frame' } + ) { + switch ($Kind) { + 'wrong correlation' { $script:events = @(New-NstEvent -CorrelationId '66666666-7777-4888-8999-aaaaaaaaaaaa') } + 'missing correlation' { $script:events = @((New-NstEvent) -replace 'ClientSessionId:', 'OtherSessionId:') } + 'stale time' { $script:events = @(New-NstEvent -Time $script:context.StartedUtc.AddTicks(-1)) } + 'future time' { $script:events = @(New-NstEvent -Time ([datetime]::UtcNow.AddHours(1))) } + 'wrong provider' { $script:events = @(New-NstEvent -Provider 'UnrelatedProvider') } + 'wrong event ID' { $script:events = @(New-NstEvent -EventId '702') } + 'wrong exception' { $script:events = @((New-NstEvent) -replace 'NullReferenceException', 'InvalidOperationException') } + 'wrong pool frame' { $script:events = @((New-NstEvent) -replace 'AcquireSqlConnectionFromPool', 'OpenConnection') } + 'wrong metadata frame' { $script:events = @((New-NstEvent) -replace 'GetRelativeHelpUrl', 'ReadMetadata') } + 'wrong OData frame' { $script:events = @((New-NstEvent) -replace 'GetNavRecordDataAsync', 'ReadSomethingElse') } + } + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + Test-Path (Join-Path $script:fixtureRoot 'SqlApiRetryEvidence') | Should -BeFalse + } + + It 'accepts an event exactly at the dispatch start boundary' { + $script:events = @(New-NstEvent -Time $script:context.StartedUtc) + Get-SqlApiTestRetryEvidence -Context $script:context | Should -Not -BeNullOrEmpty + } + + It 'fails closed with a warning for ' -ForEach @( + @{ Kind = 'missing result file' } + @{ Kind = 'malformed result XML' } + @{ Kind = 'wrong suite' } + @{ Kind = 'missing test count' } + @{ Kind = 'partial result count' } + @{ Kind = 'malformed event XML' } + @{ Kind = 'missing event system' } + @{ Kind = 'event collection access error' } + @{ Kind = 'evidence persistence failure' } + ) { + switch ($Kind) { + 'missing result file' { Remove-Item -LiteralPath $script:context.ResultFiles.JUnitResultFileName } + 'malformed result XML' { '' | Set-Content -LiteralPath $script:context.ResultFiles.JUnitResultFileName } + 'wrong suite' { + (Get-Content -LiteralPath $script:context.ResultFiles.JUnitResultFileName -Raw).Replace('70001', '70002') | + Set-Content -LiteralPath $script:context.ResultFiles.JUnitResultFileName + } + 'missing test count' { $script:context.PSObject.Properties.Remove('TestCount') } + 'partial result count' { $script:context.TestCount = 4 } + 'malformed event XML' { $script:events = @('') } + 'missing event system' { $script:events = @('') } + 'event collection access error' { Mock -ModuleName SqlApiTestRetry Get-SqlApiRetryEvents { throw 'Synthetic access denied' } } + 'evidence persistence failure' { Mock -ModuleName SqlApiTestRetry Set-Content { throw 'Synthetic write denied' } } + } + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + Should -Invoke -ModuleName SqlApiTestRetry Write-Host -Times 1 -Exactly -ParameterFilter { + $Object -like '::warning::*evidence unavailable*preserving test failure*' + } + } + + It 'fails closed with a warning when event collection returns no events' { + $script:events = @() + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + Should -Invoke -ModuleName SqlApiTestRetry Write-Host -Times 1 -Exactly -ParameterFilter { + $Object -like '::warning::*no matching NST event*' + } + } + + It 'does not retry an error element or an unrepresented failed case' -ForEach @( + @{ CaseXml = '' } + @{ CaseXml = '' } + ) { + $script:originalCases[1] = $CaseXml + Write-Suite + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + Should -Invoke -ModuleName SqlApiTestRetry Get-SqlApiRetryEvents -Times 0 + } + + It 'does not retry an already passing suite' { + Write-Suite -Cases $script:passingCases + Get-SqlApiTestRetryEvidence -Context $script:context | Should -BeNullOrEmpty + Should -Invoke -ModuleName SqlApiTestRetry Get-SqlApiRetryEvents -Times 0 + } + } + + Context 'Rerun result shape' { + It 'accepts all original full names and skip states in any order without mutating results' { + Write-Suite -Cases @($script:passingCases[2], $script:passingCases[0], $script:passingCases[1]) + $before = Get-Content -LiteralPath $script:context.ResultFiles.JUnitResultFileName -Raw + Test-SqlApiRetryResult -Context $script:context -ExpectedTests $script:expectedTests | Should -BeTrue + Get-Content -LiteralPath $script:context.ResultFiles.JUnitResultFileName -Raw | Should -Be $before + } + + It 'rejects rerun with ' -ForEach @( + @{ Kind = 'new skipped case' } + @{ Kind = 'removed original skip' } + @{ Kind = 'empty suite' } + @{ Kind = 'duplicate testcase' } + @{ Kind = 'missing testcase' } + @{ Kind = 'extra testcase' } + @{ Kind = 'renamed full testcase' } + @{ Kind = 'empty testcase name' } + @{ Kind = 'changed case in name' } + @{ Kind = 'failure element' } + @{ Kind = 'error element' } + @{ Kind = 'failed result without failure element' } + @{ Kind = 'missing result file' } + @{ Kind = 'malformed result XML' } + ) { + switch ($Kind) { + 'new skipped case' { $script:passingCases[0] = New-CaseXml -Name $script:expectedTests[0].Name -Skipped } + 'removed original skip' { $script:passingCases[2] = New-CaseXml -Name $script:expectedTests[2].Name } + 'empty suite' { $script:passingCases = @() } + 'duplicate testcase' { $script:passingCases[1] = $script:passingCases[0] } + 'missing testcase' { $script:passingCases = @($script:passingCases[0], $script:passingCases[2]) } + 'extra testcase' { $script:passingCases += New-CaseXml -Name 'Synthetic API Codeunit.Extra Case' } + 'renamed full testcase' { $script:passingCases[0] = New-CaseXml -Name 'Read Item' } + 'empty testcase name' { $script:passingCases[0] = New-CaseXml -Name '' } + 'changed case in name' { $script:passingCases[0] = New-CaseXml -Name $script:expectedTests[0].Name.ToLowerInvariant() } + 'failure element' { $script:passingCases[0] = $script:originalCases[0] } + 'error element' { $script:passingCases[0] = $script:passingCases[0].Replace('', '') } + 'failed result without failure element' { $script:passingCases[0] = New-CaseXml -Name $script:expectedTests[0].Name -Result 'Fail' } + } + Write-Suite -Cases $script:passingCases + if ($Kind -eq 'missing result file') { Remove-Item -LiteralPath $script:context.ResultFiles.JUnitResultFileName } + if ($Kind -eq 'malformed result XML') { '' | Set-Content -LiteralPath $script:context.ResultFiles.JUnitResultFileName } + Test-SqlApiRetryResult -Context $script:context -ExpectedTests $script:expectedTests | Should -BeFalse + Should -Invoke -ModuleName SqlApiTestRetry Write-Host -Times 1 -Exactly -ParameterFilter { + $Object -like '::warning::SQL API retry remains failed:*' + } + } + } + + Context 'Bounded container event collection' { + BeforeEach { + Mock -ModuleName SqlApiTestRetry Invoke-ScriptInBcContainer { + param($containerName, $scriptblock, $argumentList) + $null = $containerName + & $scriptblock @argumentList + } + Mock -ModuleName SqlApiTestRetry Get-WinEvent { @() } + } + + It 'bounds the application query by NST provider, event ID, dispatch time and maximum event count' { + $start = $script:context.StartedUtc + $end = $script:eventTime + $null = & (Get-Module SqlApiTestRetry) { + param($start, $end) + Get-SqlApiRetryEvents -ContainerName 'synthetic-container' -StartedUtc $start -FinishedUtc $end + } $start $end + Should -Invoke -ModuleName SqlApiTestRetry Invoke-ScriptInBcContainer -Times 1 -Exactly -ParameterFilter { + $containerName -eq 'synthetic-container' -and $argumentList.Count -eq 2 -and + $argumentList[0] -eq $script:context.StartedUtc.ToString('o') -and $argumentList[1] -eq $script:eventTime.ToString('o') + } + Should -Invoke -ModuleName SqlApiTestRetry Get-WinEvent -Times 1 -Exactly -ParameterFilter { + $FilterHashtable.LogName -eq 'Application' -and + $FilterHashtable.ProviderName -eq 'MicrosoftDynamicsNavServer*' -and + $FilterHashtable.Id -eq 701 -and + $FilterHashtable.StartTime -eq $script:context.StartedUtc -and + $FilterHashtable.EndTime -eq $script:eventTime -and + $MaxEvents -eq 1000 -and $ErrorAction -eq 'Stop' + } + } + + It 'returns original XML from collected events' { + $script:collectedXml = New-NstEvent + Mock -ModuleName SqlApiTestRetry Get-WinEvent { + $eventRecord = [pscustomobject]@{ Xml = $script:collectedXml } + $eventRecord | Add-Member ScriptMethod ToXml { $this.Xml } + $eventRecord + } + $actual = & (Get-Module SqlApiTestRetry) { + param($context) + Get-SqlApiRetryEvents -ContainerName $context.ContainerName -StartedUtc $context.StartedUtc -FinishedUtc ([datetime]::UtcNow) + } $script:context + $actual | Should -Be $script:collectedXml + } + + It 'treats only NoMatchingEventsFound as an empty collection' { + Mock -ModuleName SqlApiTestRetry Get-WinEvent { + $errorRecord = [System.Management.Automation.ErrorRecord]::new( + [System.Exception]::new('Synthetic no matching events'), + 'NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand', + [System.Management.Automation.ErrorCategory]::ObjectNotFound, $null) + throw $errorRecord + } + $actual = & (Get-Module SqlApiTestRetry) { + param($context) + Get-SqlApiRetryEvents -ContainerName $context.ContainerName -StartedUtc $context.StartedUtc -FinishedUtc ([datetime]::UtcNow) + } $script:context + $actual | Should -BeNullOrEmpty + } + + It 'propagates event-log access errors instead of reporting no matches' { + Mock -ModuleName SqlApiTestRetry Get-WinEvent { throw [System.UnauthorizedAccessException]::new('Synthetic event log access denied') } + { + & (Get-Module SqlApiTestRetry) { + param($context) + Get-SqlApiRetryEvents -ContainerName $context.ContainerName -StartedUtc $context.StartedUtc -FinishedUtc ([datetime]::UtcNow) + } $script:context + } | Should -Throw '*Synthetic event log access denied*' + } + } +} diff --git a/src/Apps/US/IRSForms/test/src/IRS1099APITests.Codeunit.al b/src/Apps/US/IRSForms/test/src/IRS1099APITests.Codeunit.al index 7495ec2d793..e114c4a8e6e 100644 --- a/src/Apps/US/IRSForms/test/src/IRS1099APITests.Codeunit.al +++ b/src/Apps/US/IRSForms/test/src/IRS1099APITests.Codeunit.al @@ -52,11 +52,15 @@ codeunit 148018 "IRS 1099 API Tests" IRS1099FormDocHeader: Record "IRS 1099 Form Doc. Header"; IRSReportingPeriod: Record "IRS Reporting Period"; begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IRS1099FormDocHeader.DeleteAll(true); IRSReportingPeriod.DeleteAll(true); LibraryTestInitialize.OnTestInitialize(Codeunit::"IRS 1099 API Tests"); if IsInitialized then exit; + + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"IRS 1099 API Tests"); IsInitialized := true; diff --git a/src/Apps/W1/APIV1/test/src/APIV1AccountsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1AccountsE2E.Codeunit.al index 9e3ef6f5e64..f66d536a7df 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1AccountsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1AccountsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139701 "APIV1 - Accounts E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -19,9 +20,13 @@ codeunit 139701 "APIV1 - Accounts E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1AgedAPE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1AgedAPE2E.Codeunit.al index 9c057dab240..033103a890c 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1AgedAPE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1AgedAPE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139719 "APIV1 - Aged AP E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -60,9 +61,13 @@ codeunit 139719 "APIV1 - Aged AP E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1AgedARE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1AgedARE2E.Codeunit.al index afdb729791c..a44f0646cba 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1AgedARE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1AgedARE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139720 "APIV1 - Aged AR E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -60,9 +61,13 @@ codeunit 139720 "APIV1 - Aged AR E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1AttachmentsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1AttachmentsE2E.Codeunit.al index 5e03d6caccc..27d6e6213f8 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1AttachmentsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1AttachmentsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139733 "APIV1 - Attachments E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -43,6 +44,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve all records from the Attachments API. + Initialize(); + // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateGenJournalLine(DocumentRecordRef); CreateAttachments(DocumentRecordRef, AttachmentId); @@ -65,6 +68,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve all records from the Attachments API. + Initialize(); + // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateGLEntry(DocumentRecordRef); CreateAttachments(DocumentRecordRef, AttachmentId); @@ -88,6 +93,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve all records from the Attachments API. + Initialize(); + // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); CreateAttachments(DocumentRecordRef, AttachmentId); @@ -110,6 +117,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve all records from the Attachments API. + Initialize(); + // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateDraftSalesInvoice(DocumentRecordRef); CreateAttachments(DocumentRecordRef, AttachmentId); @@ -133,6 +142,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve all records from the Attachments API. + Initialize(); + // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreatePostedPurchaseInvoice(DocumentRecordRef, DocumentId); CreateAttachments(DocumentRecordRef, AttachmentId); @@ -155,6 +166,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve all records from the Attachments API. + Initialize(); + // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateDraftPurchaseInvoice(DocumentRecordRef); CreateAttachments(DocumentRecordRef, AttachmentId); @@ -177,6 +190,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve all records from the Attachments API. + Initialize(); + // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateSalesQuote(DocumentRecordRef); CreateAttachments(DocumentRecordRef, AttachmentId); @@ -199,6 +214,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve the Attachment record from the Attachment API. + Initialize(); + // [GIVEN] Attachment exists in the Incoming Document Attachment table CreateGenJournalLine(DocumentRecordRef); AttachmentId := CreateAttachment(DocumentRecordRef); @@ -224,6 +241,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve the Attachment record from the Attachment API. + Initialize(); + // [GIVEN] Attachment exists in the Incoming Document Attachment table JournalName := LibraryUtility.GenerateRandomCode(GenJournalBatch.FieldNo(Name), Database::"Gen. Journal Batch"); LibraryAPIGeneralJournal.EnsureGenJnlBatchExists(GraphMgtJournal.GetDefaultJournalLinesTemplateName(), JournalName); @@ -249,6 +268,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve the Attachment record from the Attachment API. + Initialize(); + // [GIVEN] Attachment exists in the Incoming Document Attachment table CreateGLEntry(DocumentRecordRef); AttachmentId := CreateAttachment(DocumentRecordRef); @@ -273,6 +294,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve the Attachment record from the Attachment API. + Initialize(); + // [GIVEN] Attachment exists in the Incoming Document Attachment table CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); AttachmentId := CreateAttachment(DocumentRecordRef); @@ -296,6 +319,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve the Attachment record from the Attachment API. + Initialize(); + // [GIVEN] Attachment exists in the Incoming Document Attachment table CreateDraftSalesInvoice(DocumentRecordRef); AttachmentId := CreateAttachment(DocumentRecordRef); @@ -319,6 +344,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] User can retrieve the Attachment record from the Attachment API. + Initialize(); + // [GIVEN] Attachment exists in the Incoming Document Attachment table CreateSalesQuote(DocumentRecordRef); AttachmentId := CreateAttachment(DocumentRecordRef); @@ -346,6 +373,8 @@ codeunit 139733 "APIV1 - Attachments E2E" ActualBase64Content: Text; begin // [SCENARIO] User can update linked attachment binary content through the Attachment API. + Initialize(); + // [GIVEN] A linked attachment exists CreateGenJournalLine(DocumentRecordRef); AttachmentId := CreateAttachment(DocumentRecordRef); @@ -380,6 +409,8 @@ codeunit 139733 "APIV1 - Attachments E2E" ActualBase64Content: Text; begin // [SCENARIO] User can update linked attachment binary content through the Attachment API. + Initialize(); + // [GIVEN] A linked attachment exists CreateGLEntry(DocumentRecordRef); AttachmentId := CreateAttachment(DocumentRecordRef); @@ -407,6 +438,8 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateGenJournalLine(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -416,6 +449,8 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateGLEntry(DocumentRecordRef); TestCreateGLEAttachment(DocumentRecordRef); end; @@ -426,6 +461,8 @@ codeunit 139733 "APIV1 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); TestCreateAttachment(DocumentRecordRef, DocumentId); end; @@ -435,6 +472,8 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftSalesInvoice(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -445,6 +484,8 @@ codeunit 139733 "APIV1 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedPurchaseInvoice(DocumentRecordRef, DocumentId); TestCreateAttachment(DocumentRecordRef, DocumentId); end; @@ -454,10 +495,19 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseInvoice(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + local procedure TestCreateAttachment(var DocumentRecordRef: RecordRef) var DocumentId: Guid; @@ -555,6 +605,8 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateSalesQuote(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -564,6 +616,8 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateGenJournalLine(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -573,6 +627,8 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateGLEntry(DocumentRecordRef); TestDeleteGLEAttachment(DocumentRecordRef); end; @@ -583,6 +639,8 @@ codeunit 139733 "APIV1 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); TestDeleteAttachment(DocumentRecordRef, DocumentId); end; @@ -592,6 +650,8 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftSalesInvoice(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -602,6 +662,8 @@ codeunit 139733 "APIV1 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedPurchaseInvoice(DocumentRecordRef, DocumentId); TestDeleteAttachment(DocumentRecordRef, DocumentId); end; @@ -611,6 +673,8 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseInvoice(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -620,6 +684,8 @@ codeunit 139733 "APIV1 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateSalesQuote(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -697,6 +763,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] The Attachment is transferred from a Draft Invoice the to Posted Invoice after posting. + Initialize(); + // [GIVEN] A draft sales invoice exists. CreateDraftSalesInvoice(DocumentRecordRef); DocumentId := GetDocumentId(DocumentRecordRef); @@ -737,6 +805,8 @@ codeunit 139733 "APIV1 - Attachments E2E" TargetURL: Text; begin // [SCENARIO] The Attachment is transferred from a Draft Invoice the to Posted Invoice after posting. + Initialize(); + // [GIVEN] A draft sales invoice exists. CreateDraftPurchaseInvoice(DocumentRecordRef); DocumentId := GetDocumentId(DocumentRecordRef); @@ -779,6 +849,8 @@ codeunit 139733 "APIV1 - Attachments E2E" NewBase64Content: Text; begin // [SCENARIO] Changing an attachment file name keeps other fields unchanged + Initialize(); + // [GIVEN] A sales quote exists. CreateSalesQuote(DocumentRecordRef); DocumentId := GetDocumentId(DocumentRecordRef); @@ -824,6 +896,8 @@ codeunit 139733 "APIV1 - Attachments E2E" NewFileName: Text; begin // [SCENARIO] Changing an attachment content keeps other fields unchanged + Initialize(); + // [GIVEN] A draft sales invoice exists. CreateDraftSalesInvoice(DocumentRecordRef); DocumentId := GetDocumentId(DocumentRecordRef); @@ -862,6 +936,8 @@ codeunit 139733 "APIV1 - Attachments E2E" JSONBody: Text; begin // [SCENARIO] User cannot change the linked attachment ID by making a PATCH request to the Attachments API + Initialize(); + // [GIVEN] A sales quote exists. CreateSalesQuote(DocumentRecordRef); @@ -891,6 +967,8 @@ codeunit 139733 "APIV1 - Attachments E2E" JSONBody: Text; begin // [SCENARIO] User cannot change the attachment ID by making a PATCH request to the Attachments API + Initialize(); + // [GIVEN] Two documents exist. CreateSalesQuote(DocumentRecordRef[1]); CreateDraftSalesInvoice(DocumentRecordRef[2]); diff --git a/src/Apps/W1/APIV1/test/src/APIV1AutomationRSPackage.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1AutomationRSPackage.Codeunit.al index fba368ca1dc..b3cfb39fa44 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1AutomationRSPackage.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1AutomationRSPackage.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139731 "APIV1 - Automation RS Package" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -29,11 +30,14 @@ codeunit 139731 "APIV1 - Automation RS Package" var TenantConfigPackageFile: Record "Tenant Config. Package File"; begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); TenantConfigPackageFile.DELETEALL(TRUE); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); SamplePackageFile := GenerateSamplePackageFile(); IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1BalanceSheetE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1BalanceSheetE2E.Codeunit.al index 9f700458c0e..4864b9df7d4 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1BalanceSheetE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1BalanceSheetE2E.Codeunit.al @@ -62,9 +62,13 @@ codeunit 139715 "APIV1 - Balance Sheet E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1CashFlowStatementE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1CashFlowStatementE2E.Codeunit.al index 2478bfb256f..b147dc3c1fd 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1CashFlowStatementE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1CashFlowStatementE2E.Codeunit.al @@ -62,9 +62,13 @@ codeunit 139717 "APIV1 - CashFlow Statement E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1CompanyInfoE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1CompanyInfoE2E.Codeunit.al index 6b3b4e66322..9cd8d21baa9 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1CompanyInfoE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1CompanyInfoE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139706 "APIV1 - Company Info. E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = IntegrationTest; TestPermissions = Disabled; @@ -22,9 +23,13 @@ codeunit 139706 "APIV1 - Company Info. E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1CurrenciesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1CurrenciesE2E.Codeunit.al index 5105b4c44bb..4552658a7cc 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1CurrenciesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1CurrenciesE2E.Codeunit.al @@ -155,9 +155,13 @@ codeunit 139713 "APIV1 - Currencies E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1CustomerPaymentsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1CustomerPaymentsE2E.Codeunit.al index 13e55ac2bb6..ccac81746e9 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1CustomerPaymentsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1CustomerPaymentsE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139743 "APIV1 - Customer Payments E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -769,10 +770,14 @@ codeunit 139743 "APIV1 - Customer Payments E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryTestInitialize.OnTestInitialize(Codeunit::"APIV1 - Customer Payments E2E"); - if not isInitialized then + if not isInitialized then begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); isInitialized := true; + end; LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"APIV1 - Customer Payments E2E"); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1CustomersE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1CustomersE2E.Codeunit.al index be1fe579b35..334cc5558cc 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1CustomersE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1CustomersE2E.Codeunit.al @@ -34,9 +34,13 @@ codeunit 139702 "APIV1 - Customers E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1DefaultDimensionsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1DefaultDimensionsE2E.Codeunit.al index 96621497106..a233371f061 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1DefaultDimensionsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1DefaultDimensionsE2E.Codeunit.al @@ -37,6 +37,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the customer // [THEN] The default dimension has been added to the customer @@ -50,6 +52,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the vendor // [THEN] The default dimension has been added to the vendor @@ -63,6 +67,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Item // [THEN] The default dimension has been added to the Item @@ -89,6 +95,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the customer // [THEN] The default dimension has been added to the customer @@ -102,6 +110,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a Vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Vendor // [THEN] The default dimension has been added to the Vendor @@ -115,6 +125,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Item // [THEN] The default dimension has been added to the Item @@ -141,6 +153,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer, a dimension and a dimension value // [WHEN] a user issues a http request to create a default dimension without dimension id // [THEN] You get an error @@ -154,6 +168,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a Vendor, a dimension and a dimension value // [WHEN] a user issues a http request to create a default dimension without dimension id // [THEN] You get an error @@ -167,6 +183,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item, a dimension and a dimension value // [WHEN] a user issues a http request to create a default dimension without dimension id // [THEN] You get an error @@ -193,6 +211,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the customer, with mismatching dimesnion and dimension value // [THEN] You get an error @@ -206,6 +226,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a Vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Vendor, with mismatching dimesnion and dimension value // [THEN] You get an error @@ -219,6 +241,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Item, with mismatching dimesnion and dimension value // [THEN] You get an error @@ -245,6 +269,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension on the customer // [THEN] You get an error @@ -258,6 +284,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a Vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension on the Vendor // [THEN] You get an error @@ -271,6 +299,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension on the Item // [THEN] You get an error @@ -297,6 +327,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension value on the customer // [THEN] You get an error @@ -310,6 +342,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a Vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension value on the Vendor // [THEN] You get an error @@ -323,6 +357,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension value on the Item // [THEN] You get an error @@ -349,6 +385,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to delete the default dimension on the customer // [THEN] The default dimension has been deleted from the customer's default dimensions @@ -362,6 +400,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a Vendor with a default dimension // [WHEN] The user posts a http request to delete a default dimension on the Vendor // [THEN] The default dimension has been deleted from the vendor's default dimensions @@ -375,6 +415,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item with a default dimension // [WHEN] The user posts a http request to delete a default dimension on the Item // [THEN] The default dimension has been deleted from the item's default dimensions @@ -401,6 +443,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to get the default dimension on the customer // [THEN] The response contains the default dimension that has been added to the customer @@ -414,6 +458,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a Vendor with a default dimension // [WHEN] The user posts a http request to get a default dimension on the Vendor // [THEN] The response contains the default dimension that has been added to the Vendor @@ -427,6 +473,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item with a default dimension // [WHEN] The user posts a http request to get a default dimension on the Item // [THEN] The response contains the default dimension that has been added to the Item @@ -453,6 +501,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to patch the default dimension on the customer // [THEN] The default dimension has been updated for the customer @@ -466,6 +516,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a Vendor with a default dimension // [WHEN] The user posts a http request to patch a default dimension on the Vendor // [THEN] The default dimension has been updated for the vendor @@ -479,6 +531,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item with a default dimension // [WHEN] The user posts a http request to patch a default dimension on the Item // [THEN] The default dimension has been updated for the item @@ -505,6 +559,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to patch the default dimension with a blocked dimension value on the customer // [THEN] You get an error @@ -518,6 +574,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a Vendor with a default dimension // [WHEN] The user posts a http request to patch a default dimension with a blocked dimension value on the Vendor // [THEN] You get an error @@ -531,6 +589,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a Item with a default dimension // [WHEN] The user posts a http request to patch a default dimension with a blocked dimension value on the Item // [THEN] You get an error @@ -557,6 +617,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Customer: Record "Customer"; begin // [FEATURE] [Customer] + Initialize(); + // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to patch the default dimension with a blocked dimension value on the customer // [THEN] You get an error @@ -570,6 +632,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Vendor: Record "Vendor"; begin // [FEATURE] [Vendor] + Initialize(); + // [GIVEN] a vendor with a default dimension // [WHEN] The user posts a http request to patch the default dimension with a blocked dimension value on the vendor // [THEN] You get an error @@ -583,6 +647,8 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" Item: Record "Item"; begin // [FEATURE] [Item] + Initialize(); + // [GIVEN] a item with a default dimension // [WHEN] The user posts a http request to patch the default dimension with a blocked dimension value on the item // [THEN] You get an error @@ -603,6 +669,13 @@ codeunit 139732 "APIV1 - Default Dimensions E2E" TestPatchDefaultDimensionFailsWhenChangingDimensionCode(DATABASE::Employee, Employee."No.", Employee.SystemId); end; + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + local procedure TestCreateDefaultDimensionWithDimensionCode(TableNo: Integer; ParentNo: Code[20]; ParentId: Guid) var Dimension: Record "Dimension"; diff --git a/src/Apps/W1/APIV1/test/src/APIV1DimensionLinesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1DimensionLinesE2E.Codeunit.al index a0f0993cf2a..90bd765f3c4 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1DimensionLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1DimensionLinesE2E.Codeunit.al @@ -28,6 +28,9 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); end; [Test] @@ -44,6 +47,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" ResponseText: Text; begin // [SCENARIO] Create a dimension line in a customer payment through a POST method and check if it was created + Initialize(); LibraryGraphJournalLines.Initialize(); // [GIVEN] a journal @@ -88,6 +92,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" ResponseText: Text; begin // [SCENARIO] Creating a dimension line through a POST method without specifying a parent Id fails + Initialize(); LibraryGraphJournalLines.Initialize(); // [GIVEN] a dimension with a value @@ -119,6 +124,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" TargetURL: Text; begin // [SCENARIO] Try to create a dimension line with an already existing code + Initialize(); LibraryGraphJournalLines.Initialize(); // [GIVEN] a journal @@ -171,6 +177,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" TargetURL: Text; begin // [SCENARIO] Create dimension lines in a journal line and use a GET method to retrieve them + Initialize(); LibraryGraphJournalLines.Initialize(); // [GIVEN] a journal @@ -227,6 +234,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" TargetURL: Text; begin // [SCENARIO] Create dimension lines in a journal line and use a GET method to retrieve them + Initialize(); // [GIVEN] a customer payment in the General Journal Table LibraryGraphJournalLines.Initialize(); @@ -276,6 +284,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" TargetURL: Text; begin // [SCENARIO] Using a GET request to retrieve dimension lines without a filter fails + Initialize(); LibraryGraphJournalLines.Initialize(); AccountNo := LibraryGraphJournalLines.CreateAccount(); @@ -296,6 +305,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" TargetURL: Text; begin // [SCENARIO] Using a GET request to retrieve dimension lines with a random entity fails + Initialize(); LibraryGraphJournalLines.Initialize(); // [GIVEN] a Target URL without filters @@ -323,6 +333,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" TargetURL: Text; begin // [SCENARIO] Create a dimension line, use a PATCH method to change it and then verify the changes + Initialize(); LibraryGraphJournalLines.Initialize(); // [GIVEN] a journal @@ -386,6 +397,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" TargetURL: Text; begin // [SCENARIO] Try to change the code of an existing dimension line + Initialize(); LibraryGraphJournalLines.Initialize(); // [GIVEN] a journal @@ -444,6 +456,7 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" TargetURL: Text; begin // [SCENARIO] Create a dimension line, use a DELETE method to remove it and then verify the deletion + Initialize(); LibraryGraphJournalLines.Initialize(); // [GIVEN] a journal @@ -602,6 +615,5 @@ codeunit 139725 "APIV1 - Dimension Lines E2E" - diff --git a/src/Apps/W1/APIV1/test/src/APIV1DimensionsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1DimensionsE2E.Codeunit.al index f1aafb40161..1c92829400c 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1DimensionsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1DimensionsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139724 "APIV1 - Dimensions E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -20,9 +21,13 @@ codeunit 139724 "APIV1 - Dimensions E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1EmployeesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1EmployeesE2E.Codeunit.al index c2d3a8700fb..d64d5104e82 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1EmployeesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1EmployeesE2E.Codeunit.al @@ -25,12 +25,16 @@ codeunit 139722 "APIV1 - Employees E2E" var LibraryApplicationArea: Codeunit "Library - Application Area"; begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryApplicationArea.EnableBasicHRSetup(); // Lazy Setup. IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryHumanResource.SetupEmployeeNumberSeries(); IsInitialized := TRUE; diff --git a/src/Apps/W1/APIV1/test/src/APIV1GLEntriesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1GLEntriesE2E.Codeunit.al index f405f7a3ad5..db566bdf8bf 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1GLEntriesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1GLEntriesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139730 "APIV1 - GLEntries E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -24,10 +25,14 @@ codeunit 139730 "APIV1 - GLEntries E2E" LibraryERMCountryData: Codeunit "Library - ERM Country Data"; LibraryApplicationArea: Codeunit "Library - Application Area"; begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryApplicationArea.EnableFoundationSetup(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateVATPostingSetup(); LibraryERMCountryData.UpdateGeneralLedgerSetup(); @@ -163,4 +168,3 @@ codeunit 139730 "APIV1 - GLEntries E2E" - diff --git a/src/Apps/W1/APIV1/test/src/APIV1IncomeStatementE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1IncomeStatementE2E.Codeunit.al index a49c2db7b8b..d50fa6e693b 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1IncomeStatementE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1IncomeStatementE2E.Codeunit.al @@ -62,9 +62,13 @@ codeunit 139716 "APIV1 - Income Statement E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1ItemCategoriesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1ItemCategoriesE2E.Codeunit.al index 9035d86b098..fe9ac0f4d34 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1ItemCategoriesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1ItemCategoriesE2E.Codeunit.al @@ -155,9 +155,13 @@ codeunit 139707 "APIV1 - Item Categories E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1ItemVariantsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1ItemVariantsE2E.Codeunit.al index 7d404f44ee1..d621b0f771e 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1ItemVariantsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1ItemVariantsE2E.Codeunit.al @@ -22,6 +22,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Create an item variant through a POST method and check if it was created + Initialize(); + // [GIVEN] a JSON text with an item variant with itemId CreateItem(Item); Commit(); @@ -46,6 +48,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Cannot create an Item Variant with non-existing itemId + Initialize(); + // [GIVEN] a JSON text with an item variant with non-existing itemId ItemId := CreateGuid(); ItemVariantJSON := CreateItemVariantJsonWithItemId(ItemId, ItemVariantCode); @@ -67,6 +71,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Create an item variant through a POST method and check if it was created + Initialize(); + // [GIVEN] a JSON text with an item variant with itemNumber CreateItem(Item); Commit(); @@ -92,6 +98,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Cannot create an Item Variant with non-existing itemNumber + Initialize(); + // [GIVEN] a JSON text with an item variant with non-existing itemNumber ItemNo := LibraryUtility.GenerateRandomCode(ItemVariant.FieldNo(Code), Database::"Item Variant"); ItemVariantJSON := CreateItemVariantJsonWithItemNo(ItemNo, ItemVariantCode); @@ -113,6 +121,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Create an item variant through a POST method and check if it was created + Initialize(); + // [GIVEN] a JSON text with an item variant with itemNumber and itemId CreateItem(Item); Commit(); @@ -138,6 +148,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Cannot create an Item Variant with mismatching itemNumber and itemId + Initialize(); + // [GIVEN] a JSON text with an item variant with mismatching itemNumber and itemId CreateItem(Item1); CreateItem(Item2); @@ -161,6 +173,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Cannot create an Item Variant if there is an item variant with same itemNumber and code + Initialize(); + // [GIVEN] a JSON text with an item variant with same itemNumber and code CreateItem(Item); LibraryInventory.CreateItemVariant(ItemVariant, Item."No."); @@ -183,6 +197,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Get a simple customer with a GET request to the service. + Initialize(); + // [GIVEN] An item variant exists in the system CreateItem(Item); LibraryInventory.CreateItemVariant(ItemVariant, Item."No."); @@ -208,6 +224,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Create an item variant, use a PATCH method to change it and then verify the changes + Initialize(); + // [GIVEN] an item variant exists in the system CreateItem(Item); LibraryInventory.CreateItemVariant(ItemVariant, Item."No."); @@ -240,6 +258,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Create an item variant, use a PATCH method to change it and then verify the changes + Initialize(); + // [GIVEN] an item variant exists in the system CreateItem(Item1); CreateItem(Item2); @@ -273,6 +293,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Create an item variant, use a PATCH method to change it and then verify the changes + Initialize(); + // [GIVEN] an item variant exists in the system CreateItem(Item1); CreateItem(Item2); @@ -302,6 +324,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Create an item variant, use a DELETE method to remove it and then verify the deletion + Initialize(); + // [GIVEN] an item variant in the system CreateItem(Item); LibraryInventory.CreateItemVariant(ItemVariant, Item."No."); @@ -328,6 +352,8 @@ codeunit 139739 "APIV1 - Item Variants E2E" TargetURL: Text; begin // [SCENARIO] Cannot delete an item variant in use + Initialize(); + // [GIVEN] an item variant in the system and used in a sales order line LibraryInventory.CreateItem(Item); LibraryInventory.CreateItemVariant(ItemVariant, Item."No."); @@ -350,6 +376,13 @@ codeunit 139739 "APIV1 - Item Variants E2E" ServiceNameTxt: Label 'itemVariants'; + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + local procedure CreateItem(var Item: Record Item) begin Item.Init(); diff --git a/src/Apps/W1/APIV1/test/src/APIV1ItemsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1ItemsE2E.Codeunit.al index 4cddfa7b2ec..edba7c0d395 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1ItemsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1ItemsE2E.Codeunit.al @@ -33,9 +33,13 @@ codeunit 139700 "APIV1 - Items E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1JournalLinesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1JournalLinesE2E.Codeunit.al index c528b4c662a..2c449cfcf07 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1JournalLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1JournalLinesE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139745 "APIV1 - Journal Lines E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestType = IntegrationTest; TestPermissions = Disabled; @@ -14,8 +15,12 @@ codeunit 139745 "APIV1 - Journal Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); if IsInitialized then exit; + + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1JournalsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1JournalsE2E.Codeunit.al index 6aab2759557..87d029fe1ff 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1JournalsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1JournalsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139727 "APIV1 - Journals E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -32,9 +33,13 @@ codeunit 139727 "APIV1 - Journals E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; @@ -190,6 +195,8 @@ codeunit 139727 "APIV1 - Journals E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [GIVEN] A general journal batch with a general journal line BalAccountNo := LibraryERM.CreateGLAccountNoWithDirectPosting(); BalAccountType := GenJournalLine."Bal. Account Type"::"G/L Account"; diff --git a/src/Apps/W1/APIV1/test/src/APIV1PDFDocumentE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1PDFDocumentE2E.Codeunit.al index 3f795d60e48..5bc0a49d44b 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1PDFDocumentE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1PDFDocumentE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139744 "APIV1 - PDF Document E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -24,7 +25,9 @@ codeunit 139744 "APIV1 - PDF Document E2E" var CompanyInformation: Record "Company Information"; begin - WorkDate := Today; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryGraphMgt.SetLicenseSafeWorkDate(); CompanyInformation.Get(); if CompanyInformation."Giro No." = '' then @@ -279,4 +282,3 @@ codeunit 139744 "APIV1 - PDF Document E2E" Commit(); end; } - diff --git a/src/Apps/W1/APIV1/test/src/APIV1PaymentTermsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1PaymentTermsE2E.Codeunit.al index 5c39f3bd02a..8e2d0e50f0b 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1PaymentTermsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1PaymentTermsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139704 "APIV1 - Payment Terms E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -19,9 +20,13 @@ codeunit 139704 "APIV1 - Payment Terms E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1PicturesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1PicturesE2E.Codeunit.al index 3913b1537e6..91bb68ca5b4 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1PicturesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1PicturesE2E.Codeunit.al @@ -28,9 +28,13 @@ codeunit 139742 "APIV1 - Pictures E2E" [Scope('OnPrem')] procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; end; @@ -46,6 +50,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Customer] // [SCENARIO] Get value picture from Customer Record + Initialize(); + // [GIVEN] a customer with image attached CreateTestCustomerWithImage(Customer, TempBlobExpected); Commit(); @@ -70,6 +76,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Customer] // [SCENARIO] Get a picture metadata from Customer Record + Initialize(); + // [GIVEN] a customer with image attached CreateTestCustomerWithImage(Customer, TempBlobExpected); Commit(); @@ -93,6 +101,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Customer] // [SCENARIO] Get value picture from Customer Record when no image exist + Initialize(); + // [GIVEN] a customer without image LibrarySales.CreateCustomer(Customer); Commit(); @@ -114,6 +124,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Customer] // [SCENARIO] Get a picture metadata from Customer Record when no image is present + Initialize(); + // [GIVEN] a customer with image attached LibrarySales.CreateCustomer(Customer); Commit(); @@ -139,6 +151,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Customer] // [SCENARIO] Set Picture on a customer without picture + Initialize(); + // [GIVEN] a customer with image attached LibrarySales.CreateCustomer(Customer); GetRedImageTempBlob(TempBlobExpected); @@ -171,6 +185,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Customer] // [SCENARIO] Replace the Picture on a customer + Initialize(); + // [GIVEN] a customer with image attached CreateTestCustomerWithImage(Customer, TempBlobOriginal); GetBlueImageTempBlob(TempBlobExpected); @@ -202,6 +218,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Customer] // [SCENARIO] Replace the Picture on a customer + Initialize(); + // [GIVEN] a customer with image attached CreateTestCustomerWithImage(Customer, TempBlobOriginal); GetBlueImageTempBlob(TempBlobExpected); @@ -229,6 +247,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Vendor] // [SCENARIO] Get value picture from Vendor Record + Initialize(); + // [GIVEN] a Vendor with image attached CreateTestVendorWithImage(Vendor, TempBlobExpected); Commit(); @@ -253,6 +273,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Vendor] // [SCENARIO] Get a picture metadata from Vendor Record + Initialize(); + // [GIVEN] a Vendor with image attached CreateTestVendorWithImage(Vendor, TempBlobExpected); Commit(); @@ -276,6 +298,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Vendor] // [SCENARIO] Get value picture from Vendor Record when no image exist + Initialize(); + // [GIVEN] a Vendor without image LibraryPurchase.CreateVendor(Vendor); Commit(); @@ -297,6 +321,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Vendor] // [SCENARIO] Get a picture metadata from Vendor Record when no image is present + Initialize(); + // [GIVEN] a Vendor with image attached LibraryPurchase.CreateVendor(Vendor); Commit(); @@ -322,6 +348,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Vendor] // [SCENARIO] Set Picture on a Vendor without picture + Initialize(); + // [GIVEN] a Vendor with image attached LibraryPurchase.CreateVendor(Vendor); GetRedImageTempBlob(TempBlobExpected); @@ -354,6 +382,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Vendor] // [SCENARIO] Replace the Picture on a Vendor + Initialize(); + // [GIVEN] a Vendor with image attached CreateTestVendorWithImage(Vendor, TempBlobOriginal); GetBlueImageTempBlob(TempBlobExpected); @@ -385,6 +415,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Vendor] // [SCENARIO] Replace the Picture on a Vendor + Initialize(); + // [GIVEN] a Vendor with image attached CreateTestVendorWithImage(Vendor, TempBlobOriginal); GetBlueImageTempBlob(TempBlobExpected); @@ -412,6 +444,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Employee] // [SCENARIO] Get value picture from Employee Record + Initialize(); + // [GIVEN] an Employee with image attached CreateTestEmployeeWithImage(Employee, TempBlobExpected); Commit(); @@ -436,6 +470,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Employee] // [SCENARIO] Get a picture metadata from Employee Record + Initialize(); + // [GIVEN] a Employee with image attached CreateTestEmployeeWithImage(Employee, TempBlobExpected); Commit(); @@ -459,6 +495,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Employee] // [SCENARIO] Get value picture from Employee Record when no image exist + Initialize(); + // [GIVEN] a Employee without image LibraryHumanResource.CreateEmployee(Employee); Commit(); @@ -480,6 +518,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Employee] // [SCENARIO] Get a picture metadata from Employee Record when no image is present + Initialize(); + // [GIVEN] a Employee with image attached LibraryHumanResource.CreateEmployee(Employee); Commit(); @@ -505,6 +545,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Employee] // [SCENARIO] Set Picture on a Employee without picture + Initialize(); + // [GIVEN] a Employee with image attached LibraryHumanResource.CreateEmployee(Employee); GetRedImageTempBlob(TempBlobExpected); @@ -537,6 +579,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Employee] // [SCENARIO] Replace the Picture on a Employee + Initialize(); + // [GIVEN] a Employee with image attached CreateTestEmployeeWithImage(Employee, TempBlobOriginal); GetBlueImageTempBlob(TempBlobExpected); @@ -568,6 +612,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Employee] // [SCENARIO] Replace the Picture on a Employee + Initialize(); + // [GIVEN] a Employee with image attached CreateTestEmployeeWithImage(Employee, TempBlobOriginal); GetBlueImageTempBlob(TempBlobExpected); @@ -595,6 +641,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Item] // [SCENARIO] Get value picture from Item Record + Initialize(); + // [GIVEN] a Item with image attached CreateTestItemWithImage(Item, TempBlobExpected); Commit(); @@ -619,6 +667,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Item] // [SCENARIO] Get a picture metadata from Item Record + Initialize(); + // [GIVEN] a Item with image attached CreateTestItemWithImage(Item, TempBlobExpected); Commit(); @@ -642,6 +692,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Item] // [SCENARIO] Get value picture from Item Record when no image exist + Initialize(); + // [GIVEN] a Item without image LibraryInventory.CreateItem(Item); Commit(); @@ -663,6 +715,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Item] // [SCENARIO] Get a picture metadata from Item Record when no image is present + Initialize(); + // [GIVEN] a Item with image attached LibraryInventory.CreateItem(Item); Commit(); @@ -688,6 +742,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Item] // [SCENARIO] Set Picture on a Item without picture + Initialize(); + // [GIVEN] a Item with image attached LibraryInventory.CreateItem(Item); GetRedImageTempBlob(TempBlobExpected); @@ -720,6 +776,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Item] // [SCENARIO] Replace the Picture on a Item + Initialize(); + // [GIVEN] a Item with image attached CreateTestItemWithImage(Item, TempBlobOriginal); GetBlueImageTempBlob(TempBlobExpected); @@ -751,6 +809,8 @@ codeunit 139742 "APIV1 - Pictures E2E" // [FEATURE] [Item] // [SCENARIO] Replace the Picture on a Item + Initialize(); + // [GIVEN] a Item with image attached CreateTestItemWithImage(Item, TempBlobOriginal); GetBlueImageTempBlob(TempBlobExpected); diff --git a/src/Apps/W1/APIV1/test/src/APIV1PurchaseInvLinesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1PurchaseInvLinesE2E.Codeunit.al index d3b95c6f61c..0a4f6a11fce 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1PurchaseInvLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1PurchaseInvLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139738 "APIV1 - Purchase Inv Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -31,9 +32,13 @@ codeunit 139738 "APIV1 - Purchase Inv Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); LibraryERMCountryData.CreateGeneralPostingSetupData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); @@ -1149,12 +1154,6 @@ codeunit 139738 "APIV1 - Purchase Inv Lines E2E" - - - - - - diff --git a/src/Apps/W1/APIV1/test/src/APIV1PurchaseInvoicesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1PurchaseInvoicesE2E.Codeunit.al index 8060fbf4d23..2914b56908b 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1PurchaseInvoicesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1PurchaseInvoicesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139729 "APIV1 - Purchase Invoices E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -34,6 +35,9 @@ codeunit 139729 "APIV1 - Purchase Invoices E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); end; [Test] diff --git a/src/Apps/W1/APIV1/test/src/APIV1RetEarningsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1RetEarningsE2E.Codeunit.al index 2bc76f8cb32..88a90cebf09 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1RetEarningsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1RetEarningsE2E.Codeunit.al @@ -62,9 +62,13 @@ codeunit 139721 "APIV1 - Ret. Earnings E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1SalesCrMemoLinesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1SalesCrMemoLinesE2E.Codeunit.al index 1d5fc4dabe1..615c7c0e9bb 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1SalesCrMemoLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1SalesCrMemoLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139737 "APIV1 - Sales CrMemo Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -30,9 +31,13 @@ codeunit 139737 "APIV1 - Sales CrMemo Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibrarySales.SetStockoutWarning(FALSE); LibraryApplicationArea.EnableFoundationSetup(); @@ -1392,12 +1397,6 @@ codeunit 139737 "APIV1 - Sales CrMemo Lines E2E" - - - - - - diff --git a/src/Apps/W1/APIV1/test/src/APIV1SalesCreditMemosE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1SalesCreditMemosE2E.Codeunit.al index 8ab2dff2dbb..70b9714f81e 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1SalesCreditMemosE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1SalesCreditMemosE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -35,6 +36,13 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" CreditMemoStatusErr: Label 'The credit memo status is incorrect.'; MailingJobErr: Label 'The mailing job is not created.', Locked = true; + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + local procedure InitializeForSending() var TempEmailAccount: Record "Email Account"; @@ -60,6 +68,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO] Create posted and unposted sales credit memos and use a GET method to retrieve them + Initialize(); + // [GIVEN] 2 credit memos, one posted and one unposted CreateSalesCreditMemos(CreditMemoNo1, CreditMemoNo2); COMMIT(); @@ -93,6 +103,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO] Create posted and unposted Sales credit memos and use HTTP POST to delete them + Initialize(); + // [GIVEN] 2 credit memos, one posted and one unposted LibrarySales.CreateCustomerWithAddress(SellToCustomer); LibrarySales.CreateCustomerWithAddress(BillToCustomer); @@ -138,6 +150,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO] Create posted and unposted with specific currency set and use HTTP POST to create them + Initialize(); + // [GIVEN] an CreditMemo with a non-LCY currencyCode set LibrarySales.CreateCustomer(Customer); CustomerNo := Customer."No."; @@ -168,18 +182,24 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" [Test] procedure TestModifyCreditMemos() begin + Initialize(); + TestMultipleModifyCreditMemos(FALSE, FALSE); end; [Test] procedure TestEmptyModifyCreditMemos() begin + Initialize(); + TestMultipleModifyCreditMemos(TRUE, FALSE); end; [Test] procedure TestPartialModifyCreditMemos() begin + Initialize(); + TestMultipleModifyCreditMemos(FALSE, TRUE); end; @@ -263,6 +283,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO] Create unposted sales credit memo and use HTTP DELETE to delete it + Initialize(); + // [GIVEN] An unposted credit memo CreateDraftSalesCreditMemo(SalesHeader); CreditMemoNo := SalesHeader."No."; @@ -296,6 +318,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" // [SCENARIO] Create an credit memo both through the client UI and through the API // [SCENARIO] and compare them. They should be the same and have the same fields autocompleted wherever needed. + Initialize(); + // [GIVEN] An unposted credit memo LibraryGraphDocumentTools.InitializeUIPage(); @@ -329,6 +353,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO] When an credit memo is created,the GET Method should update the credit memo and assign a total + Initialize(); + // [GIVEN] 2 credit memos, one posted and one unposted without totals assigned LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending( SalesHeader, DiscountPct, SalesHeader."Document Type"::"Credit Memo"); @@ -362,6 +388,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO] When an credit memo is created, the GET Method should update the credit memo and assign a total + Initialize(); + // [GIVEN] 2 credit memos, one posted and one unposted with discount amount that should be redistributed LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending( SalesHeader, DiscountPct, SalesHeader."Document Type"::"Credit Memo"); @@ -401,6 +429,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" CreditMemoID: Text; begin // [SCENARIO 184721] Create Credit Memo, use a PATCH method to change it and then verify the changes + Initialize(); + LibrarySales.CreateCustomerWithAddress(Customer); // [GIVEN] an item with unit price and unit cost @@ -448,6 +478,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO 184721] Clearing manually set discount + Initialize(); + // [GIVEN] an item with unit price and unit cost LibraryInventory.CreateItemWithUnitPriceAndUnitCost( Item, LibraryRandom.RandDecInRange(1, 100, 2), LibraryRandom.RandDecInRange(1, 100, 2)); @@ -503,6 +535,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO] User can post a sales credit memo through the API. + Initialize(); + // [GIVEN] Draft sales credit memo exists CreateDraftSalesCreditMemo(SalesHeader); SetCustomerEmail(SalesHeader."Sell-to Customer No."); @@ -549,6 +583,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" TargetURL: Text; begin // [SCENARIO] User can post and send a sales credit memo through the API. + Initialize(); + InitializeForSending(); // [GIVEN] Draft sales credit memos exists @@ -588,6 +624,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO] User can cancel a posted sales credit memo through API. + Initialize(); + // [GIVEN] Non-corrective sales credit memo exists CreatePostedSalesCreditMemo(SalesCrMemoHeader); SetCustomerEmail(SalesCrMemoHeader."Sell-to Customer No."); @@ -617,6 +655,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" begin // [SCENARIO] User can cancel a posted sales credit memo through API. + Initialize(); + // [GIVEN] Corrective sales credit memo exists CreateCorrectiveSalesCreditMemo(SalesCrMemoHeader); SetCustomerEmail(SalesCrMemoHeader."Sell-to Customer No."); @@ -649,6 +689,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" TargetURL: Text; begin // [SCENARIO] User can cancel a posted sales credit memo through API. + Initialize(); + InitializeForSending(); // [GIVEN] Corrective sales credit memo exists @@ -685,6 +727,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" TargetURL: Text; begin // [SCENARIO] User can send a posted sales credit memo through the API. + Initialize(); + InitializeForSending(); // [GIVEN] Posted sales credit memo exists @@ -717,6 +761,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" TargetURL: Text; begin // [SCENARIO] Sending a draft sales credit memo through the API throws an error + Initialize(); + InitializeForSending(); // [GIVEN] Draft sales credit memo exists @@ -746,6 +792,8 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" TargetURL: Text; begin // [SCENARIO] User can send a draft sales credit memo through the API. + Initialize(); + InitializeForSending(); // [GIVEN] Cancelled sales credit memo exists @@ -1071,4 +1119,3 @@ codeunit 139728 "APIV1 - Sales Credit Memos E2E" JobQueueEntry.Cancel(); end; } - diff --git a/src/Apps/W1/APIV1/test/src/APIV1SalesInvLinesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1SalesInvLinesE2E.Codeunit.al index 86e95b3f302..75853b94e50 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1SalesInvLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1SalesInvLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139734 "APIV1 - Sales Inv. Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -33,9 +34,13 @@ codeunit 139734 "APIV1 - Sales Inv. Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibrarySales.SetStockoutWarning(FALSE); LibraryApplicationArea.EnableFoundationSetup(); diff --git a/src/Apps/W1/APIV1/test/src/APIV1SalesOrderLinesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1SalesOrderLinesE2E.Codeunit.al index 2afa4cf7193..8615ed84e08 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1SalesOrderLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1SalesOrderLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139735 "APIV1 - Sales Order Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -31,9 +32,13 @@ codeunit 139735 "APIV1 - Sales Order Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibrarySales.SetStockoutWarning(FALSE); LibraryApplicationArea.EnableFoundationSetup(); @@ -1279,14 +1284,6 @@ codeunit 139735 "APIV1 - Sales Order Lines E2E" - - - - - - - - diff --git a/src/Apps/W1/APIV1/test/src/APIV1SalesOrdersE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1SalesOrdersE2E.Codeunit.al index ec9fb22f169..f9a02ff432e 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1SalesOrdersE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1SalesOrdersE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139711 "APIV1 - Sales Orders E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -40,6 +41,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO 184721] Create Sales Orders and use a GET method to retrieve them + Initialize(); + // [GIVEN] 2 orders in the table LibrarySales.CreateSalesOrder(SalesHeader); OrderNo[1] := SalesHeader."No."; @@ -78,6 +81,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO 184721] Create sales orders JSON and use HTTP POST to create them + Initialize(); + // [GIVEN] a customer LibrarySales.CreateCustomerWithAddress(SellToCustomer); LibrarySales.CreateCustomerWithAddress(BillToCustomer); @@ -127,6 +132,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO 184721] Create sales order for customer with location and use HTTP POST to create it + Initialize(); + // [GIVEN] an order with customer with location code LibrarySales.CreateCustomer(Customer); LibraryWarehouse.CreateLocation(Location); @@ -170,6 +177,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO 184721] Create sales order with specific currency set and use HTTP POST to create it + Initialize(); + // [GIVEN] an order with a non-LCY currencyCode set LibrarySales.CreateCustomer(Customer); CustomerNo := Customer."No."; @@ -203,21 +212,34 @@ codeunit 139711 "APIV1 - Sales Orders E2E" [Test] procedure TestModifyOrders() begin + Initialize(); + TestMultipleModifyOrders(false, false); end; [Test] procedure TestEmptyModifyOrders() begin + Initialize(); + TestMultipleModifyOrders(true, false); end; [Test] procedure TestPartialModifyOrders() begin + Initialize(); + TestMultipleModifyOrders(false, true); end; + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + local procedure TestMultipleModifyOrders(EmptyData: Boolean; PartiallyEmptyData: Boolean) var SellToCustomer: Record "Customer"; @@ -291,6 +313,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO 184721] Create sales orders and use HTTP DELETE to delete them + Initialize(); + // [GIVEN] 2 orders in the table LibrarySales.CreateSalesOrder(SalesHeader); OrderNo[1] := SalesHeader."No."; @@ -336,6 +360,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" OrderWithComplexJSON: Text; begin // [SCENARIO 184721] Create an order both through the client UI and through the API and compare them. They should be the same and have the same fields autocompleted wherever needed. + Initialize(); + LibraryGraphDocumentTools.InitializeUIPage(); // [GIVEN] a customer @@ -396,6 +422,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO 184721] When an order is created, the GET Method should update the order and assign a total + Initialize(); + // [GIVEN] an order without totals assigned LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending(SalesHeader, DiscountPct, SalesHeader."Document Type"::Order); SalesHeader.CalcFields("Recalculate Invoice Disc."); @@ -426,6 +454,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO 184721] When an order is created, the GET Method should update the order and redistribute the discount amount + Initialize(); + // [GIVEN] an order with discount amount that should be redistributed LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending(SalesHeader, DiscountPct, SalesHeader."Document Type"::Order); SalesHeader.CalcFields(Amount); @@ -461,6 +491,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO 184721] Create Sales Order, use a PATCH method to change it and then verify the changes + Initialize(); + // [GIVEN] an order with lines CreateOrderWithLines(SalesHeader); OrderId := SalesHeader.SystemId; @@ -497,6 +529,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO 184721] Clearing manually set discount + Initialize(); + // [GIVEN] an order CreateOrderWithLines(SalesHeader); OrderNo := SalesHeader."No."; @@ -533,6 +567,8 @@ codeunit 139711 "APIV1 - Sales Orders E2E" begin // [SCENARIO] User can ship and invoice a sales order through the API. + Initialize(); + // [GIVEN] a sales order with lines CreateOrderWithLines(SalesHeader); OrderId := SalesHeader.SystemId; diff --git a/src/Apps/W1/APIV1/test/src/APIV1SalesQuoteLinesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1SalesQuoteLinesE2E.Codeunit.al index b4e577f634b..d1d53b26e59 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1SalesQuoteLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1SalesQuoteLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139736 "APIV1 - Sales Quote Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -29,9 +30,13 @@ codeunit 139736 "APIV1 - Sales Quote Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibrarySales.SetStockoutWarning(FALSE); LibraryApplicationArea.EnableFoundationSetup(); @@ -1005,12 +1010,6 @@ codeunit 139736 "APIV1 - Sales Quote Lines E2E" - - - - - - diff --git a/src/Apps/W1/APIV1/test/src/APIV1SalesQuotesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1SalesQuotesE2E.Codeunit.al index b395b79b8e8..065c83792a9 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1SalesQuotesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1SalesQuotesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -39,6 +40,13 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" InvoiceIdErr: Label 'The invoice ID should differ from the quote ID.', Locked = true; MailingJobErr: Label 'The mailing job is not created.', Locked = true; + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + local procedure InitializeForSending() var TempEmailAccount: Record "Email Account"; @@ -64,6 +72,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" begin // [SCENARIO] Create Sales Quotes and use a GET method to retrieve them + Initialize(); + // [GIVEN] 2 quotes in the table CreateSalesQuoteWithLines(SalesHeader); QuoteID[1] := SalesHeader."No."; @@ -102,6 +112,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" begin // [SCENARIO] Create sales quotes JSON and use HTTP POST to create them + Initialize(); + // [GIVEN] a customer LibrarySales.CreateCustomerWithAddress(SellToCustomer); LibrarySales.CreateCustomerWithAddress(ShipToCustomer); @@ -147,6 +159,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" begin // [SCENARIO] Create sales quote with specific currency set and use HTTP POST to create it + Initialize(); + // [GIVEN] a quote with a non-LCY currencyCode set LibrarySales.CreateCustomer(Customer); CustomerNo := Customer."No."; @@ -176,18 +190,24 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" [Test] procedure TestModifyQuotes() begin + Initialize(); + TestMultipleModifyQuotes(false, false); end; [Test] procedure TestEmptyModifyQuotes() begin + Initialize(); + TestMultipleModifyQuotes(true, false); end; [Test] procedure TestPartialModifyQuotes() begin + Initialize(); + TestMultipleModifyQuotes(false, true); end; @@ -281,6 +301,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" begin // [SCENARIO] Create sales quotes and use HTTP DELETE to delete them + Initialize(); + // [GIVEN] 2 quotes in the table CreateSalesQuoteWithLines(SalesHeader); QuoteID[1] := SalesHeader."No."; @@ -326,6 +348,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" QuoteExists: Boolean; begin // [SCENARIO] Create a quote both through the client UI and through the API and compare them. They should be the same and have the same fields autocompleted wherever needed. + Initialize(); + LibraryGraphDocumentTools.InitializeUIPage(); // [GIVEN] a customer @@ -381,6 +405,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" begin // [SCENARIO] When a quote is created, the GET Method should update the quote and assign a total + Initialize(); + // [GIVEN] a quote without totals assigned LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending(SalesHeader, DiscountPct, SalesHeader."Document Type"::Quote); SalesHeader.CalcFields("Recalculate Invoice Disc."); @@ -411,6 +437,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" begin // [SCENARIO] When a quote is created, the GET Method should update the quote and redistribute the discount amount + Initialize(); + // [GIVEN] a quote with discount amount that should be redistributed LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending(SalesHeader, DiscountPct, SalesHeader."Document Type"::Quote); SalesHeader.CalcFields(Amount); @@ -447,6 +475,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" QuoteID: Text; begin // [SCENARIO 184721] Create Sales Quote, use a PATCH method to change it and then verify the changes + Initialize(); + LibrarySales.CreateCustomerWithAddress(Customer); // [GIVEN] an item with unit price and unit cost @@ -494,6 +524,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" begin // [SCENARIO 184721] Clearing manually set discount + Initialize(); + // [GIVEN] an item with unit price and unit cost LibraryInventory.CreateItemWithUnitPriceAndUnitCost( Item, LibraryRandom.RandDecInRange(1, 100, 2), LibraryRandom.RandDecInRange(1, 100, 2)); @@ -541,6 +573,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" TargetURL: Text; begin // [SCENARIO] User can send a sales quote through the API. + Initialize(); + InitializeForSending(); // [GIVEN] Draft sales quote exists @@ -585,6 +619,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" begin // [SCENARIO] User can convert a sales quote to a sales invoice through the API. + Initialize(); + // [GIVEN] Sales quote exists CreateSalesQuoteWithLines(SalesHeader); CreateEmailParameters(SalesHeader); @@ -643,6 +679,8 @@ codeunit 139723 "APIV1 - Sales Quotes E2E" begin // [SCENARIO] User can convert a sales quote to a sales order through the API. + Initialize(); + // [GIVEN] Sales quote exists CreateSalesQuoteWithLines(SalesHeader); CreateEmailParameters(SalesHeader); diff --git a/src/Apps/W1/APIV1/test/src/APIV1ShipmentMethodsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1ShipmentMethodsE2E.Codeunit.al index 09cf7ce2b3e..57274730dea 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1ShipmentMethodsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1ShipmentMethodsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139705 "APIV1 - Shipment Methods E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -21,9 +22,13 @@ codeunit 139705 "APIV1 - Shipment Methods E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1TaxAreasE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1TaxAreasE2E.Codeunit.al index bffc2b39d55..9bc959cb00b 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1TaxAreasE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1TaxAreasE2E.Codeunit.al @@ -24,9 +24,13 @@ codeunit 139726 "APIV1 - Tax Areas E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1TrialBalanceE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1TrialBalanceE2E.Codeunit.al index c495bc2ddfc..f03565d2c42 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1TrialBalanceE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1TrialBalanceE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139718 "APIV1 - Trial Balance E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -60,9 +61,13 @@ codeunit 139718 "APIV1 - Trial Balance E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/APIV1UofME2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1UofME2E.Codeunit.al index b283bc61d9d..8eacc612fb0 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1UofME2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1UofME2E.Codeunit.al @@ -26,6 +26,8 @@ codeunit 139712 "APIV1 - UofM E2E" begin // [SCENARIO] User can get the units of measure. + Initialize(); + // [GIVEN] Units of measure. GenerateUnitsOfMeasure(UnitOfMeasure, 5); @@ -46,6 +48,8 @@ codeunit 139712 "APIV1 - UofM E2E" begin // [SCENARIO] User can update a unit of measure. + Initialize(); + // [GIVEN] Units of measure. GenerateUnitsOfMeasure(UnitOfMeasure, 5); @@ -75,6 +79,8 @@ codeunit 139712 "APIV1 - UofM E2E" begin // [SCENARIO] User can delete a unit of measure. + Initialize(); + // [GIVEN] Units of measure. GenerateUnitsOfMeasure(UnitOfMeasure, 5); @@ -96,6 +102,8 @@ codeunit 139712 "APIV1 - UofM E2E" begin // [SCENARIO] User can insert a unit of measure. + Initialize(); + // [GIVEN] A new unit of measure. GenerateUnitOfMeasure(UnitOfMeasure); Request := CreateInsertUnitOfMeasureRequest(UnitOfMeasure); @@ -111,6 +119,13 @@ codeunit 139712 "APIV1 - UofM E2E" ValidateUnitOfMeasure(UnitOfMeasure, Response); end; + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + local procedure GenerateUnitsOfMeasure(var UnitOfMeasure: Record "Unit of Measure"; "Count": Integer) var i: Integer; diff --git a/src/Apps/W1/APIV1/test/src/APIV1VendorsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/APIV1VendorsE2E.Codeunit.al index 44570b29311..05fdec9f1e3 100644 --- a/src/Apps/W1/APIV1/test/src/APIV1VendorsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/APIV1VendorsE2E.Codeunit.al @@ -25,9 +25,13 @@ codeunit 139703 "APIV1 - Vendors E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV1/test/src/CountriesRegionsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/CountriesRegionsE2E.Codeunit.al index 1e4843ec39c..d2f70856614 100644 --- a/src/Apps/W1/APIV1/test/src/CountriesRegionsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/CountriesRegionsE2E.Codeunit.al @@ -155,9 +155,13 @@ codeunit 139710 "Countries/Regions E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/PaymentMethodsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/PaymentMethodsE2E.Codeunit.al index 005c5f0add8..b454803fcee 100644 --- a/src/Apps/W1/APIV1/test/src/PaymentMethodsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/PaymentMethodsE2E.Codeunit.al @@ -155,9 +155,13 @@ codeunit 139714 "Payment Methods E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; end; diff --git a/src/Apps/W1/APIV1/test/src/SalesInvoicesE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/SalesInvoicesE2E.Codeunit.al index dbf39f9a725..549feabec64 100644 --- a/src/Apps/W1/APIV1/test/src/SalesInvoicesE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/SalesInvoicesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139709 "Sales Invoices E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -48,6 +49,13 @@ codeunit 139709 "Sales Invoices E2E" NotEmptyParameterErr: Label 'Email parameter %1 is not empty.', Locked = true; MailingJobErr: Label 'The mailing job is not created.', Locked = true; + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + local procedure InitializeForSending() var TempEmailAccount: Record "Email Account"; @@ -73,6 +81,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO 184721] Create posted and unposted Sales invoices and use a GET method to retrieve them + Initialize(); + // [GIVEN] 2 invoices, one posted and one unposted CreateSalesInvoices(InvoiceID1, InvoiceID2); COMMIT(); @@ -106,6 +116,8 @@ codeunit 139709 "Sales Invoices E2E" InvoiceWithComplexJSON: Text; begin // [SCENARIO 184721] Create posted and unposted Sales invoices and use HTTP POST to delete them + Initialize(); + // [GIVEN] 2 invoices, one posted and one unposted LibrarySales.CreateCustomer(SellToCustomer); @@ -157,6 +169,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO 184721] Create posted and unposted with specific currency set and use HTTP POST to create them + Initialize(); + // [GIVEN] an Invoice with a non-LCY currencyCode set LibrarySales.CreateCustomer(Customer); CustomerNo := Customer."No."; @@ -203,6 +217,8 @@ codeunit 139709 "Sales Invoices E2E" CurrencyCode: Code[10]; begin // [SCENARIO 285872] Create posted and unposted with specific email set and use HTTP POST to create them + Initialize(); + Email := 'test@microsoft.com'; // [GIVEN] an Customer with no email set @@ -256,6 +272,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO 184721] Create unposted with specific document and due date set and use HTTP POST to create them + Initialize(); + // [GIVEN] an Invoice with a document and due date set LibrarySales.CreateCustomer(Customer); CustomerNo := Customer."No."; @@ -294,18 +312,24 @@ codeunit 139709 "Sales Invoices E2E" [Test] procedure TestModifyInvoices() begin + Initialize(); + TestMultipleModifyInvoices(FALSE, FALSE); end; [Test] procedure TestEmptyModifyInvoices() begin + Initialize(); + TestMultipleModifyInvoices(TRUE, FALSE); end; [Test] procedure TestPartialModifyInvoices() begin + Initialize(); + TestMultipleModifyInvoices(FALSE, TRUE); end; @@ -405,6 +429,8 @@ codeunit 139709 "Sales Invoices E2E" InvoiceWithBlanksJSON: Text; begin // [SCENARIO 184721] Create Sales Invoice with all the Ids filled, use a PATCH method to blank the Ids and the Codes + Initialize(); + LibrarySales.CreateCustomerWithAddress(Customer); // [GIVEN] a currency @@ -470,6 +496,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO 184721] Create draft invoice and issue a patch request to change the number + Initialize(); + // [GIVEN] 1 draft invoice and a json with a new number LibrarySales.CreateSalesInvoice(SalesHeader); NewInvoiceNumber := COPYSTR(CREATEGUID(), 1, MAXSTRLEN(SalesHeader."No.")); @@ -493,6 +521,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO 184721] Create unposted Sales invoice and use HTTP DELETE to delete it + Initialize(); + // [GIVEN] An unposted invoice CreateDraftSalesInvoice(SalesHeader); InvoiceID := SalesHeader."No."; @@ -532,6 +562,8 @@ codeunit 139709 "Sales Invoices E2E" // [SCENARIO 184721] Create an invoice both through the client UI and through the API // [SCENARIO] and compare them. They should be the same and have the same fields autocompleted wherever needed. + Initialize(); + // [GIVEN] An unposted invoice LibraryGraphDocumentTools.InitializeUIPage(); LibraryApplicationArea.DisableApplicationAreaSetup(); @@ -594,6 +626,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO 184721] When an invoice is created,the GET Method should update the invoice and assign a total + Initialize(); + // [GIVEN] 2 invoices, one posted and one unposted without totals assigned LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending( SalesHeader, DiscountPct, SalesHeader."Document Type"::Invoice); @@ -627,6 +661,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO 184721] When an invoice is created, the GET Method should update the invoice and assign a total + Initialize(); + // [GIVEN] 2 invoices, one posted and one unposted with discount amount that should be redistributed LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending( SalesHeader, DiscountPct, SalesHeader."Document Type"::Invoice); @@ -663,6 +699,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO 184721] Create an invoice wihtout Customer throws an error + Initialize(); + // [GIVEN] a sales invoice JSON with currency only Currency.SETFILTER(Code, '<>%1', ''); Currency.FINDFIRST(); @@ -690,6 +728,8 @@ codeunit 139709 "Sales Invoices E2E" InvoiceID: Text; begin // [SCENARIO 184721] Create Sales Invoice, use a PATCH method to change it and then verify the changes + Initialize(); + LibrarySales.CreateCustomerWithAddress(Customer); // [GIVEN] an item with unit price and unit cost @@ -737,6 +777,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO 184721] Clearing manually set discount + Initialize(); + // [GIVEN] an item with unit price and unit cost LibraryInventory.CreateItemWithUnitPriceAndUnitCost( Item, LibraryRandom.RandDecInRange(1, 100, 2), LibraryRandom.RandDecInRange(1, 100, 2)); @@ -793,6 +835,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO] User can post a sales invoice through the API. + Initialize(); + // [GIVEN] Draft sales invoice exists CreateDraftSalesInvoice(SalesHeader); DraftInvoiceRecordRef.GetTable(SalesHeader); @@ -838,6 +882,8 @@ codeunit 139709 "Sales Invoices E2E" TargetURL: Text; begin // [SCENARIO] User can post and send a sales invoice through the API. + Initialize(); + InitializeForSending(); // [GIVEN] Draft sales invoice exists @@ -877,6 +923,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO] User can cancel a posted sales invoice through API. + Initialize(); + // [GIVEN] Posted sales invoice exists CreatePostedSalesInvoice(SalesInvoiceHeader); SetCustomerEmail(SalesInvoiceHeader."Sell-to Customer No."); @@ -912,6 +960,8 @@ codeunit 139709 "Sales Invoices E2E" TargetURL: Text; begin // [SCENARIO] User can cancel a posted sales invoice through API. + Initialize(); + InitializeForSending(); // [GIVEN] Posted sales invoice exists @@ -952,6 +1002,8 @@ codeunit 139709 "Sales Invoices E2E" TargetURL: Text; begin // [SCENARIO] User can send a posted sales invoice through the API. + Initialize(); + InitializeForSending(); // [GIVEN] Posted sales invoice exists @@ -984,6 +1036,8 @@ codeunit 139709 "Sales Invoices E2E" TargetURL: Text; begin // [SCENARIO] User can send a draft sales invoice through the API. + Initialize(); + InitializeForSending(); // [GIVEN] Draft sales invoice exists @@ -1016,6 +1070,8 @@ codeunit 139709 "Sales Invoices E2E" TargetURL: Text; begin // [SCENARIO] User can send a draft sales invoice through the API. + Initialize(); + InitializeForSending(); // [GIVEN] Cancelled sales invoice exists @@ -1057,6 +1113,8 @@ codeunit 139709 "Sales Invoices E2E" begin // [SCENARIO] User can create a corrective credit memo for the posted sales invoice through the API. + Initialize(); + // [GIVEN] A posted sales invoice exists CreatePostedSalesInvoice(SalesInvoiceHeader); PostedInvoiceRecordRef.GetTable(SalesInvoiceHeader); diff --git a/src/Apps/W1/APIV1/test/src/TaxGroupsE2E.Codeunit.al b/src/Apps/W1/APIV1/test/src/TaxGroupsE2E.Codeunit.al index 15b2166d131..cfa2ea66f1f 100644 --- a/src/Apps/W1/APIV1/test/src/TaxGroupsE2E.Codeunit.al +++ b/src/Apps/W1/APIV1/test/src/TaxGroupsE2E.Codeunit.al @@ -23,9 +23,13 @@ codeunit 139708 "Tax Groups E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); IF IsInitialized THEN EXIT; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := TRUE; COMMIT(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2AccountingPeriodsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2AccountingPeriodsE2E.Codeunit.al index c578df54f2d..5cd61faa5b2 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2AccountingPeriodsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2AccountingPeriodsE2E.Codeunit.al @@ -16,6 +16,8 @@ codeunit 139859 "APIV2 - Accounting Periods E2E" TargetURL: Text; i: Integer; begin + Initialize(); + // [SCENARIO] Use a GET method to retrieve all accounting periods // [GIVEN] Accounting Periods for i := 1 to 10 do @@ -74,4 +76,11 @@ codeunit 139859 "APIV2 - Accounting Periods E2E" AccountingPeriod.Insert(true); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2AccountsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2AccountsE2E.Codeunit.al index 9389de358ba..fb16bde22f0 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2AccountsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2AccountsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139801 "APIV2 - Accounts E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -19,9 +20,14 @@ codeunit 139801 "APIV2 - Accounts E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; @@ -106,4 +112,3 @@ codeunit 139801 "APIV2 - Accounts E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2AgedAPE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2AgedAPE2E.Codeunit.al index 2418082ad5b..4d45914cd1b 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2AgedAPE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2AgedAPE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139819 "APIV2 - Aged AP E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -60,9 +61,14 @@ codeunit 139819 "APIV2 - Aged AP E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := true; end; @@ -82,4 +88,3 @@ codeunit 139819 "APIV2 - Aged AP E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2AgedARE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2AgedARE2E.Codeunit.al index 2a280d83eb5..2ff3d83ba67 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2AgedARE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2AgedARE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139820 "APIV2 - Aged AR E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -60,9 +61,14 @@ codeunit 139820 "APIV2 - Aged AR E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := true; end; @@ -81,4 +87,3 @@ codeunit 139820 "APIV2 - Aged AR E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2ApplyVendorEntE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2ApplyVendorEntE2E.Codeunit.al index 4b30e2db6ef..70032165f9a 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2ApplyVendorEntE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2ApplyVendorEntE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139867 "APIV2 - Apply Vendor Ent. E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -170,10 +171,15 @@ codeunit 139867 "APIV2 - Apply Vendor Ent. E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryTestInitialize.OnTestInitialize(Codeunit::"APIV2 - Apply Vendor Ent. E2E"); - if not isInitialized then + if not isInitialized then begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); isInitialized := true; + end; LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"APIV2 - Apply Vendor Ent. E2E"); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2ApprovalEntriesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2ApprovalEntriesE2E.Codeunit.al index 9ae78501641..39745d47677 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2ApprovalEntriesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2ApprovalEntriesE2E.Codeunit.al @@ -1,6 +1,5 @@ codeunit 139917 "APIV2 - Approval Entries E2E" { - Subtype = Test; TestType = IntegrationTest; TestPermissions = Disabled; @@ -22,6 +21,8 @@ codeunit 139917 "APIV2 - Approval Entries E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO] Check that approval entries can be retrieved via API // [GIVEN] a Sales order exists @@ -44,4 +45,10 @@ codeunit 139917 "APIV2 - Approval Entries E2E" Assert.IsTrue(LibraryGraphMgt.GetObjectIDFromJSON(ResponseText, 'id', ApprovalEntryId), 'Could not find approval entry'); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } \ No newline at end of file diff --git a/src/Apps/W1/APIV2/test/src/APIV2ApprovalUserSetupE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2ApprovalUserSetupE2E.Codeunit.al index 2a259376141..148da74e16c 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2ApprovalUserSetupE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2ApprovalUserSetupE2E.Codeunit.al @@ -1,6 +1,5 @@ codeunit 139918 "APIV2 - Approval UserSetup E2E" { - Subtype = Test; TestType = IntegrationTest; TestPermissions = Disabled; @@ -20,6 +19,8 @@ codeunit 139918 "APIV2 - Approval UserSetup E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO] Check that approval user setup can be retrieved via API // [GIVEN] an Approval User Setup exists @@ -39,4 +40,10 @@ codeunit 139918 "APIV2 - Approval UserSetup E2E" Assert.IsTrue(LibraryGraphMgt.GetObjectIDFromJSON(ResponseText, 'id', UserSetupId), 'Could not find approval user setup'); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } \ No newline at end of file diff --git a/src/Apps/W1/APIV2/test/src/APIV2AssemblyOrdersE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2AssemblyOrdersE2E.Codeunit.al index 9de9e6343ae..9c274228e3e 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2AssemblyOrdersE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2AssemblyOrdersE2E.Codeunit.al @@ -26,6 +26,8 @@ codeunit 139925 "APIV2 - Assembly Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create an assembly order and use GET to retrieve it // [GIVEN] An assembly order LibraryInventory.CreateItem(Item); @@ -48,6 +50,8 @@ codeunit 139925 "APIV2 - Assembly Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create an assembly order and GET it by SystemId // [GIVEN] An assembly order LibraryInventory.CreateItem(Item); @@ -72,6 +76,8 @@ codeunit 139925 "APIV2 - Assembly Orders E2E" TargetURL: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] GET an assembly order with $expand=dimensionSetLines // [GIVEN] An assembly order if not AssemblyHeader.FindFirst() then begin @@ -99,6 +105,8 @@ codeunit 139925 "APIV2 - Assembly Orders E2E" TargetURL: Text; AttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET an assembly order with $expand=attachments // [GIVEN] An assembly order if not AssemblyHeader.FindFirst() then begin @@ -126,6 +134,8 @@ codeunit 139925 "APIV2 - Assembly Orders E2E" TargetURL: Text; DocumentAttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET an assembly order with $expand=documentAttachments // [GIVEN] An assembly order if not AssemblyHeader.FindFirst() then begin @@ -153,6 +163,8 @@ codeunit 139925 "APIV2 - Assembly Orders E2E" TargetURL: Text; PdfDocumentValue: Text; begin + Initialize(); + // [SCENARIO] GET an assembly order with $expand=pdfDocument // [GIVEN] An assembly order if not AssemblyHeader.FindFirst() then begin @@ -180,6 +192,8 @@ codeunit 139925 "APIV2 - Assembly Orders E2E" TargetURL: Text; LinesValue: Text; begin + Initialize(); + // [SCENARIO] GET an assembly order with $expand=assemblyOrderLines // [GIVEN] An assembly order if not AssemblyHeader.FindFirst() then begin @@ -204,4 +218,11 @@ codeunit 139925 "APIV2 - Assembly Orders E2E" exit(TargetURL + '&$expand=' + ExpandValue); exit(TargetURL + '?$expand=' + ExpandValue); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2AttachmentsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2AttachmentsE2E.Codeunit.al index 0ba1716ac2d..8aaa574e8c8 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2AttachmentsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2AttachmentsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139833 "APIV2 - Attachments E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -42,6 +43,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateGenJournalLine(DocumentRecordRef); @@ -65,6 +68,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table GLEntryGuid := CreateGLEntry(DocumentRecordRef); @@ -88,6 +93,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); @@ -110,6 +117,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateDraftSalesInvoice(DocumentRecordRef); @@ -132,6 +141,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateDraftSalesOrder(DocumentRecordRef); @@ -156,6 +167,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreatePostedPurchaseInvoice(DocumentRecordRef, DocumentId); @@ -178,6 +191,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateDraftPurchaseInvoice(DocumentRecordRef); @@ -200,6 +215,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateSalesQuote(DocumentRecordRef); @@ -222,6 +239,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Incoming Document Attachment table CreateGenJournalLine(DocumentRecordRef); @@ -246,6 +265,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Incoming Document Attachment table JournalName := LibraryUtility.GenerateRandomCode(GenJournalBatch.FieldNo(Name), Database::"Gen. Journal Batch"); @@ -272,6 +293,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Incoming Document Attachment table CreateGLEntry(DocumentRecordRef); @@ -295,6 +318,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Incoming Document Attachment table CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); @@ -317,6 +342,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Incoming Document Attachment table CreateDraftSalesInvoice(DocumentRecordRef); @@ -339,6 +366,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Incoming Document Attachment table CreateDraftSalesOrder(DocumentRecordRef); @@ -361,6 +390,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Incoming Document Attachment table CreateSalesQuote(DocumentRecordRef); @@ -383,6 +414,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateDraftPurchaseOrder(DocumentRecordRef); @@ -409,6 +442,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ExpectedBase64Content: Text; ActualBase64Content: Text; begin + Initialize(); + // [SCENARIO] User can update linked attachment binary content through the Attachment API. // [GIVEN] A linked attachment exists CreateGenJournalLine(DocumentRecordRef); @@ -442,6 +477,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ExpectedBase64Content: Text; ActualBase64Content: Text; begin + Initialize(); + // [SCENARIO] User can update linked attachment binary content through the Attachment API. // [GIVEN] A linked attachment exists CreateGLEntry(DocumentRecordRef); @@ -468,6 +505,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateGenJournalLine(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -477,6 +516,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateGLEntry(DocumentRecordRef); TestCreateGLEAttachment(DocumentRecordRef); end; @@ -487,6 +528,8 @@ codeunit 139833 "APIV2 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); TestCreateAttachment(DocumentRecordRef); end; @@ -496,6 +539,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftSalesInvoice(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -505,6 +550,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftSalesOrder(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -515,6 +562,8 @@ codeunit 139833 "APIV2 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedPurchaseInvoice(DocumentRecordRef, DocumentId); TestCreateAttachment(DocumentRecordRef); end; @@ -524,6 +573,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseInvoice(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -533,6 +584,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseOrder(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -634,6 +687,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateSalesQuote(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -643,6 +698,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateGenJournalLine(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -652,6 +709,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateGLEntry(DocumentRecordRef); TestDeleteGLEAttachment(DocumentRecordRef); end; @@ -662,6 +721,8 @@ codeunit 139833 "APIV2 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); TestDeleteAttachment2(DocumentRecordRef); end; @@ -671,6 +732,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftSalesInvoice(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -681,6 +744,8 @@ codeunit 139833 "APIV2 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedPurchaseInvoice(DocumentRecordRef, DocumentId); TestDeleteAttachment2(DocumentRecordRef); end; @@ -690,6 +755,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseInvoice(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -699,6 +766,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateSalesQuote(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -773,6 +842,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] The Attachment is transferred from a Draft Invoice the to Posted Invoice after posting. // [GIVEN] A draft sales invoice exists. CreateDraftSalesInvoice(DocumentRecordRef); @@ -813,6 +884,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] The Attachment is transferred from a Draft Invoice the to Posted Invoice after posting. // [GIVEN] A draft sales invoice exists. CreateDraftPurchaseInvoice(DocumentRecordRef); @@ -855,6 +928,8 @@ codeunit 139833 "APIV2 - Attachments E2E" OldBase64Content: Text; NewBase64Content: Text; begin + Initialize(); + // [SCENARIO] Changing an attachment file name keeps other fields unchanged // [GIVEN] A sales quote exists. CreateSalesQuote(DocumentRecordRef); @@ -899,6 +974,8 @@ codeunit 139833 "APIV2 - Attachments E2E" OldFileName: Text; NewFileName: Text; begin + Initialize(); + // [SCENARIO] Changing an attachment content keeps other fields unchanged // [GIVEN] A draft sales invoice exists. CreateDraftSalesInvoice(DocumentRecordRef); @@ -937,6 +1014,8 @@ codeunit 139833 "APIV2 - Attachments E2E" TargetURL: Text; JSONBody: Text; begin + Initialize(); + // [SCENARIO] User cannot change the attachment ID by making a PATCH request to the Attachments API // [GIVEN] Two documents exist. CreateSalesQuote(DocumentRecordRef[1]); @@ -967,6 +1046,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreatePostedPurchaseCreditMemo(DocumentRecordRef, DocumentId); @@ -989,6 +1070,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Incoming Document Attachment table CreateDraftPurchaseCreditMemo(DocumentRecordRef); @@ -1009,6 +1092,8 @@ codeunit 139833 "APIV2 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedPurchaseCreditMemo(DocumentRecordRef, DocumentId); TestCreateAttachment(DocumentRecordRef); end; @@ -1018,6 +1103,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseCreditMemo(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -1028,6 +1115,8 @@ codeunit 139833 "APIV2 - Attachments E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedPurchaseCreditMemo(DocumentRecordRef, DocumentId); TestDeleteAttachment2(DocumentRecordRef); end; @@ -1037,6 +1126,8 @@ codeunit 139833 "APIV2 - Attachments E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseCreditMemo(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -1054,6 +1145,8 @@ codeunit 139833 "APIV2 - Attachments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] The Attachment is transferred from a Draft Credit Memo the to Posted Credit Memo after posting. // [GIVEN] A draft purchase credit memo exists. LibraryERMCountryData.UpdatePurchasesPayablesSetup(); @@ -1592,4 +1685,11 @@ codeunit 139833 "APIV2 - Attachments E2E" exit(StrSubstNo('%1.%2', Name, Extension)); exit(Name); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2AutomationRSPackage.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2AutomationRSPackage.Codeunit.al index 31c14c5d3ab..8da2f4675b5 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2AutomationRSPackage.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2AutomationRSPackage.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139831 "APIV2 - Automation RS Package" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -28,8 +29,11 @@ codeunit 139831 "APIV2 - Automation RS Package" var TenantConfigPackageFile: Record "Tenant Config. Package File"; begin - TenantConfigPackageFile.DELETEALL(true); + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + TenantConfigPackageFile.DELETEALL(true); SamplePackageFile := GenerateSamplePackageFile(); end; @@ -354,6 +358,5 @@ codeunit 139831 "APIV2 - Automation RS Package" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2BalanceSheetE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2BalanceSheetE2E.Codeunit.al index f99099da896..704b3a4619e 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2BalanceSheetE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2BalanceSheetE2E.Codeunit.al @@ -62,9 +62,14 @@ codeunit 139815 "APIV2 - Balance Sheet E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := true; end; @@ -88,4 +93,3 @@ codeunit 139815 "APIV2 - Balance Sheet E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2BlPurchOrdersE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2BlPurchOrdersE2E.Codeunit.al index 25dbc2bfd72..0509ddb1263 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2BlPurchOrdersE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2BlPurchOrdersE2E.Codeunit.al @@ -24,6 +24,8 @@ codeunit 139908 "APIV2 - Bl. Purch. Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a blanket purchase order and use GET to retrieve it // [GIVEN] A blanket purchase order LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::"Blanket Order", ''); @@ -44,6 +46,8 @@ codeunit 139908 "APIV2 - Bl. Purch. Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a blanket purchase order and GET it by SystemId // [GIVEN] A blanket purchase order LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::"Blanket Order", ''); @@ -66,6 +70,8 @@ codeunit 139908 "APIV2 - Bl. Purch. Orders E2E" TargetURL: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket purchase order with $expand=dimensionSetLines // [GIVEN] A blanket purchase order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Blanket Order"); @@ -92,6 +98,8 @@ codeunit 139908 "APIV2 - Bl. Purch. Orders E2E" TargetURL: Text; AttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket purchase order with $expand=attachments // [GIVEN] A blanket purchase order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Blanket Order"); @@ -118,6 +126,8 @@ codeunit 139908 "APIV2 - Bl. Purch. Orders E2E" TargetURL: Text; DocumentAttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket purchase order with $expand=documentAttachments // [GIVEN] A blanket purchase order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Blanket Order"); @@ -144,6 +154,8 @@ codeunit 139908 "APIV2 - Bl. Purch. Orders E2E" TargetURL: Text; PdfDocumentValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket purchase order with $expand=pdfDocument // [GIVEN] A blanket purchase order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Blanket Order"); @@ -170,6 +182,8 @@ codeunit 139908 "APIV2 - Bl. Purch. Orders E2E" TargetURL: Text; LinesValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket purchase order with $expand=blanketPurchaseOrderLines // [GIVEN] A blanket purchase order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Blanket Order"); @@ -194,4 +208,10 @@ codeunit 139908 "APIV2 - Bl. Purch. Orders E2E" exit(TargetURL + '&$expand=' + ExpandValue); exit(TargetURL + '?$expand=' + ExpandValue); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2BlSalesOrdersE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2BlSalesOrdersE2E.Codeunit.al index e70ad8a2eb3..111a07def07 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2BlSalesOrdersE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2BlSalesOrdersE2E.Codeunit.al @@ -24,6 +24,8 @@ codeunit 139909 "APIV2 - Bl. Sales Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a blanket sales order and use GET to retrieve it // [GIVEN] A blanket sales order LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Blanket Order", ''); @@ -44,6 +46,8 @@ codeunit 139909 "APIV2 - Bl. Sales Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a blanket sales order and GET it by SystemId // [GIVEN] A blanket sales order LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Blanket Order", ''); @@ -66,6 +70,8 @@ codeunit 139909 "APIV2 - Bl. Sales Orders E2E" TargetURL: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket sales order with $expand=dimensionSetLines // [GIVEN] A blanket sales order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Blanket Order"); @@ -92,6 +98,8 @@ codeunit 139909 "APIV2 - Bl. Sales Orders E2E" TargetURL: Text; AttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket sales order with $expand=attachments // [GIVEN] A blanket sales order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Blanket Order"); @@ -118,6 +126,8 @@ codeunit 139909 "APIV2 - Bl. Sales Orders E2E" TargetURL: Text; DocumentAttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket sales order with $expand=documentAttachments // [GIVEN] A blanket sales order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Blanket Order"); @@ -144,6 +154,8 @@ codeunit 139909 "APIV2 - Bl. Sales Orders E2E" TargetURL: Text; PdfDocumentValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket sales order with $expand=pdfDocument // [GIVEN] A blanket sales order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Blanket Order"); @@ -170,6 +182,8 @@ codeunit 139909 "APIV2 - Bl. Sales Orders E2E" TargetURL: Text; LinesValue: Text; begin + Initialize(); + // [SCENARIO] GET a blanket sales order with $expand=blanketSalesOrderLines // [GIVEN] A blanket sales order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Blanket Order"); @@ -194,4 +208,10 @@ codeunit 139909 "APIV2 - Bl. Sales Orders E2E" exit(TargetURL + '&$expand=' + ExpandValue); exit(TargetURL + '?$expand=' + ExpandValue); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2CashFlowStatementE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2CashFlowStatementE2E.Codeunit.al index 9ff2fa17758..7912cf90a97 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2CashFlowStatementE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2CashFlowStatementE2E.Codeunit.al @@ -62,9 +62,14 @@ codeunit 139817 "APIV2 - CashFlow Statement E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := true; end; @@ -93,4 +98,3 @@ codeunit 139817 "APIV2 - CashFlow Statement E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2CompanyInfoE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2CompanyInfoE2E.Codeunit.al index 295e9a9dc83..857e1986a88 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2CompanyInfoE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2CompanyInfoE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139806 "APIV2 - Company Info. E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = IntegrationTest; TestPermissions = Disabled; @@ -24,9 +25,14 @@ codeunit 139806 "APIV2 - Company Info. E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2ContactsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2ContactsE2E.Codeunit.al index 431c3a98b1c..f4515ca11e4 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2ContactsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2ContactsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139866 "APIV2 - Contacts E2E" // version Test,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -22,9 +23,14 @@ codeunit 139866 "APIV2 - Contacts E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2ContactsInfE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2ContactsInfE2E.Codeunit.al index 5612f0eb26c..e4978df62f7 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2ContactsInfE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2ContactsInfE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139853 "APIV2 - Contacts Inf. E2E" // version Test,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -30,6 +31,8 @@ codeunit 139853 "APIV2 - Contacts Inf. E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [FEATURE] [Customer] // [SCENARIO] Get all contact information for a customer @@ -60,6 +63,8 @@ codeunit 139853 "APIV2 - Contacts Inf. E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [FEATURE] [Customer] // [SCENARIO] Get all contact information for a customer @@ -92,6 +97,8 @@ codeunit 139853 "APIV2 - Contacts Inf. E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [FEATURE] [Vendor] // [SCENARIO] Get all contact information for a vendor @@ -122,6 +129,8 @@ codeunit 139853 "APIV2 - Contacts Inf. E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [FEATURE] [Vendor] // [SCENARIO] Get all contact information for a Vendor @@ -177,4 +186,11 @@ codeunit 139853 "APIV2 - Contacts Inf. E2E" Contact.Validate("Company No.", CompanyNo); Contact.Modify(true); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2CountriesRegionsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2CountriesRegionsE2E.Codeunit.al index 0bd63f98d47..b18c1157647 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2CountriesRegionsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2CountriesRegionsE2E.Codeunit.al @@ -155,9 +155,14 @@ codeunit 139810 "APIV2 - Countries/Regions E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; end; @@ -233,4 +238,3 @@ codeunit 139810 "APIV2 - Countries/Regions E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2CurrenciesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2CurrenciesE2E.Codeunit.al index 5e8bfb987bc..8b81ce31b02 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2CurrenciesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2CurrenciesE2E.Codeunit.al @@ -155,9 +155,14 @@ codeunit 139813 "APIV2 - Currencies E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; end; @@ -232,4 +237,3 @@ codeunit 139813 "APIV2 - Currencies E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2CurrencyExchRateE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2CurrencyExchRateE2E.Codeunit.al index 36e62a1b344..045094549f7 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2CurrencyExchRateE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2CurrencyExchRateE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139858 "APIV2 Currency Exch. Rate E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; var LibraryERM: Codeunit "Library - ERM"; @@ -107,6 +108,10 @@ codeunit 139858 "APIV2 Currency Exch. Rate E2E" Currency: Record Currency; CurrencyExchangeRate: Record "Currency Exchange Rate"; begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + Currency.DeleteAll(); CurrencyExchangeRate.DeleteAll(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2CustRetReasonsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2CustRetReasonsE2E.Codeunit.al index 5749e8a0fb7..806cc6bad24 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2CustRetReasonsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2CustRetReasonsE2E.Codeunit.al @@ -22,9 +22,14 @@ codeunit 139869 "APIV2 - Cust. Ret. Reasons E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2CustomerPaymentsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2CustomerPaymentsE2E.Codeunit.al index b2e150e30af..5f93c91aede 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2CustomerPaymentsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2CustomerPaymentsE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139840 "APIV2 - Customer Payments E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -769,10 +770,14 @@ codeunit 139840 "APIV2 - Customer Payments E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryTestInitialize.OnTestInitialize(Codeunit::"APIV2 - Customer Payments E2E"); - if not isInitialized then + if not isInitialized then begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); isInitialized := true; + end; LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"APIV2 - Customer Payments E2E"); end; @@ -806,4 +811,3 @@ codeunit 139840 "APIV2 - Customer Payments E2E" exit(ServiceSubpageNameTxt + '(' + LibraryGraphMgt.StripBrackets(CustomerPaymentId) + ')'); end; } - diff --git a/src/Apps/W1/APIV2/test/src/APIV2CustomersE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2CustomersE2E.Codeunit.al index 567d0166f0a..f0156c35d4c 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2CustomersE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2CustomersE2E.Codeunit.al @@ -34,9 +34,14 @@ codeunit 139802 "APIV2 - Customers E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2DefaultDimensionsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2DefaultDimensionsE2E.Codeunit.al index 5a72973f69d..edc80adba49 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2DefaultDimensionsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2DefaultDimensionsE2E.Codeunit.al @@ -35,6 +35,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the customer @@ -48,6 +49,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the vendor @@ -61,6 +63,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Item @@ -74,6 +77,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a Employee, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Employee @@ -87,6 +91,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the customer @@ -100,6 +105,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a Vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Vendor @@ -113,6 +119,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Item @@ -126,6 +133,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a Employee, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Employee @@ -139,6 +147,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the customer, with mismatching dimesnion and dimension value @@ -152,6 +161,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a Vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Vendor, with mismatching dimesnion and dimension value @@ -165,6 +175,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Item, with mismatching dimesnion and dimension value @@ -178,6 +189,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a Employee, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension on the Employee, with mismatching dimesnion and dimension value @@ -191,6 +203,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension on the customer @@ -204,6 +217,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a Vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension on the Vendor @@ -217,6 +231,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension on the Item @@ -230,6 +245,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a Employee, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension on the Employee @@ -243,6 +259,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension value on the customer @@ -256,6 +273,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a Vendor, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension value on the Vendor @@ -269,6 +287,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a Item, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension value on the Item @@ -282,6 +301,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a Employee, a dimension and a dimension value // [WHEN] The user posts a http request to create a default dimension with a blocked dimension value on the Employee @@ -295,6 +315,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to delete the default dimension on the customer @@ -308,6 +329,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a Vendor with a default dimension // [WHEN] The user posts a http request to delete a default dimension on the Vendor @@ -321,6 +343,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a Item with a default dimension // [WHEN] The user posts a http request to delete a default dimension on the Item @@ -334,6 +357,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a Employee with a default dimension // [WHEN] The user posts a http request to delete a default dimension on the Employee @@ -347,6 +371,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to get the default dimension on the customer @@ -360,6 +385,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a Vendor with a default dimension // [WHEN] The user posts a http request to get a default dimension on the Vendor @@ -373,6 +399,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a Item with a default dimension // [WHEN] The user posts a http request to get a default dimension on the Item @@ -386,6 +413,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a Employee with a default dimension // [WHEN] The user posts a http request to get a default dimension on the Employee @@ -399,6 +427,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to patch the default dimension on the customer @@ -412,6 +441,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a Vendor with a default dimension // [WHEN] The user posts a http request to patch a default dimension on the Vendor @@ -425,6 +455,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a Item with a default dimension // [WHEN] The user posts a http request to patch a default dimension on the Item @@ -438,6 +469,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a Employee with a default dimension // [WHEN] The user posts a http request to patch a default dimension on the Employee @@ -451,6 +483,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to patch the default dimension with a blocked dimension value on the customer @@ -464,6 +497,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a Vendor with a default dimension // [WHEN] The user posts a http request to patch a default dimension with a blocked dimension value on the Vendor @@ -477,6 +511,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a Item with a default dimension // [WHEN] The user posts a http request to patch a default dimension with a blocked dimension value on the Item @@ -490,6 +525,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a Employee with a default dimension // [WHEN] The user posts a http request to patch a default dimension with a blocked dimension value on the Employee @@ -503,6 +539,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Customer: Record "Customer"; begin + Initialize(); // [FEATURE] [Customer] // [GIVEN] a customer with a default dimension // [WHEN] The user posts a http request to patch the default dimension with a blocked dimension value on the customer @@ -516,6 +553,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Vendor: Record "Vendor"; begin + Initialize(); // [FEATURE] [Vendor] // [GIVEN] a vendor with a default dimension // [WHEN] The user posts a http request to patch the default dimension with a blocked dimension value on the vendor @@ -529,6 +567,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Item: Record "Item"; begin + Initialize(); // [FEATURE] [Item] // [GIVEN] a item with a default dimension // [WHEN] The user posts a http request to patch the default dimension with a blocked dimension value on the item @@ -542,6 +581,7 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" var Employee: Record "Employee"; begin + Initialize(); // [FEATURE] [Employee] // [GIVEN] a employee with a default dimension // [WHEN] The user posts a http request to patch the default dimension with a blocked dimension value on the employee @@ -561,6 +601,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" DimensionValueId: Text; ParentIdAsText: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); ParentIdAsText := LowerCase(Format(ParentId)); @@ -592,6 +634,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" DimensionId: Text; DimensionValueId: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); ParentIdAsText := LowerCase(Format(ParentId)); @@ -624,6 +668,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" DimensionId: Text; DimensionValue2Id: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); LibraryDimension.CreateDimension(Dimension2); @@ -653,6 +699,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" DimensionId: Text; DimensionValueId: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); Dimension.Validate(Blocked, true); @@ -682,6 +730,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" DimensionId: Text; DimensionValueId: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); DimensionValue.Validate(Blocked, true); @@ -711,6 +761,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" ParentIdAsText: Text; DimensionId: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); DefaultDimension.Validate("Table ID", TableNo); @@ -748,6 +800,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" DimensionId: Text; DimensionValueId: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); DefaultDimension.Validate("Table ID", TableNo); @@ -785,6 +839,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" DimensionId: Text; DimensionValue2Id: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); LibraryDimension.CreateDimensionValue(DimensionValue2, Dimension.Code); @@ -826,6 +882,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" DimensionId: Text; DimensionValue2Id: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); LibraryDimension.CreateDimensionValue(DimensionValue2, Dimension.Code); @@ -866,6 +924,8 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" ParentIdAsText: Text; DimensionId: Text; begin + Initialize(); + LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimension(Dimension2); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); @@ -975,4 +1035,11 @@ codeunit 139832 "APIV2 - Default Dimensions E2E" end; exit(DefaultDimensionParentType::" "); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2DimSetLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2DimSetLinesE2E.Codeunit.al index 503e68355db..fcdecceeafb 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2DimSetLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2DimSetLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -28,6 +29,9 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); end; [Test] @@ -38,6 +42,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" JournalName: Code[10]; JournalLineGUID: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in journal through a POST method and check if it was created LibraryGraphJournalLines.Initialize(); @@ -62,6 +67,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales order and a sales order line through a POST method and check if it was created // [GIVEN] A sales order LibrarySales.CreateSalesOrder(SalesHeader); @@ -90,6 +96,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineId: Guid; CustomerNo: Code[20]; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales quote and sales quote line through a POST method and check if it was created // [GIVEN] A sales quote LibrarySales.CreateCustomer(Customer); @@ -118,6 +125,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales credit memo and a sales cr memo line through a POST method and check if it was created // [GIVEN] A sales credit memo LibrarySales.CreateSalesCreditMemo(SalesHeader); @@ -144,6 +152,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales invoice and a sales invoice line through a POST method and check if it was created // [GIVEN] A sales invoice LibrarySales.CreateSalesInvoice(SalesHeader); @@ -170,6 +179,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a purchase invoice and a purchase invoice line through a POST method and check if it was created // [GIVEN] A purchase invoice LibraryPurchase.CreatePurchaseInvoice(PurchaseHeader); @@ -196,6 +206,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a purchase order and a purchase order line through a POST method and check if it was created // [GIVEN] A purchase order LibraryPurchase.CreatePurchaseOrder(PurchaseHeader); @@ -222,6 +233,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" DocumentRecordRef: RecordRef; TimeSheetDetailId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a time registration entry through a POST method and check if it was created // [GIVEN] A Time registration entry UserSetup.DeleteAll(); @@ -242,6 +254,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO] Creating a dimension line through a POST method without specifying a parent Id fails LibraryGraphJournalLines.Initialize(); @@ -273,6 +287,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Try to create a dimension line with an already existing code LibraryGraphJournalLines.Initialize(); @@ -318,6 +334,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" JournalName: Code[10]; JournalLineGUID: Guid; begin + Initialize(); // [SCENARIO] Create dimension lines in a journal line and use a GET method to retrieve them // [GIVEN] a journal in the General Journal Table LibraryGraphJournalLines.Initialize(); @@ -335,6 +352,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" SalesLine: Record "Sales Line"; LineId: Guid; begin + Initialize(); // [SCENARIO] Create dimension lines in a sales order and sales order line and use a GET method to retrieve them // [GIVEN] a sales order with lines LibrarySales.CreateSalesOrder(SalesHeader); @@ -358,6 +376,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" CustomerNo: Code[20]; LineId: Guid; begin + Initialize(); // [SCENARIO] Create dimension lines in a sales quote and sales quote line and use a GET method to retrieve them // [GIVEN] a sales quote with lines LibrarySales.CreateCustomer(Customer); @@ -381,6 +400,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" SalesLine: Record "Sales Line"; LineId: Guid; begin + Initialize(); // [SCENARIO] Create dimension lines in a sales cr memo and sales cr memo line and use a GET method to retrieve them // [GIVEN] a sales cr memo with lines LibrarySales.CreateSalesCreditMemo(SalesHeader); @@ -402,6 +422,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" SalesLine: Record "Sales Line"; LineId: Guid; begin + Initialize(); // [SCENARIO] Create dimension lines in a sales invoice and sales invoice line and use a GET method to retrieve them // [GIVEN] a sales invoice with lines LibrarySales.CreateSalesInvoice(SalesHeader); @@ -423,6 +444,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" PurchaseLine: Record "Purchase Line"; LineId: Guid; begin + Initialize(); // [SCENARIO] Create dimension lines in a pucrhase invoice and purchase invoice line and use a GET method to retrieve them // [GIVEN] a purchase invoice with lines LibraryPurchase.CreatePurchaseInvoice(PurchaseHeader); @@ -444,6 +466,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" PurchaseLine: Record "Purchase Line"; LineId: Guid; begin + Initialize(); // [SCENARIO] Create dimension lines in a pucrhase order and purchase order line and use a GET method to retrieve them // [GIVEN] a purchase order with lines LibraryPurchase.CreatePurchaseOrder(PurchaseHeader); @@ -467,6 +490,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" DocumentRecordRef: RecordRef; TimeSheetDetailId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a time registration entry through a POST method and and use a GET method to retrieve them // [GIVEN] A Time registration entry UserSetup.DeleteAll(); @@ -491,6 +515,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" TargetURL: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] Create a G/L Entry with dimenions after Posting Sales Invoice and use a GET method to retreive them // [GIVEN] Create Customer, Items and Sales Invoice for different Items. @@ -522,6 +548,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Using a GET request to retrieve dimension lines without a filter fails LibraryGraphJournalLines.Initialize(); @@ -544,6 +572,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" JournalName: Code[10]; JournalLineGUID: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line, use a PATCH method to change it and then verify the changes LibraryGraphJournalLines.Initialize(); @@ -565,6 +594,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales order and a sales order line, use a PATCH method to change it and then verify the changes // [GIVEN] A sales order LibrarySales.CreateSalesOrder(SalesHeader); @@ -593,6 +623,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineId: Guid; CustomerNo: Code[20]; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales quote and a sales quote line, use a PATCH method to change it and then verify the changes // [GIVEN] A sales quote LibrarySales.CreateCustomer(Customer); @@ -621,6 +652,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales credit memo and a sales cr memo line, use a PATCH method to change it and then verify the changes // [GIVEN] A sales credit memo LibrarySales.CreateSalesCreditMemo(SalesHeader); @@ -647,6 +679,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales invoice and a sales invoice line, use a PATCH method to change it and then verify the changes // [GIVEN] A sales invoice LibrarySales.CreateSalesInvoice(SalesHeader); @@ -673,6 +706,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a purchase invoice and a purchase invoice line, use a PATCH method to change it and then verify the changes // [GIVEN] A purchase invoice LibraryPurchase.CreatePurchaseInvoice(PurchaseHeader); @@ -699,6 +733,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a purchase order and a purchase order line, use a PATCH method to change it and then verify the changes // [GIVEN] A purchase order LibraryPurchase.CreatePurchaseOrder(PurchaseHeader); @@ -725,6 +760,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" DocumentRecordRef: RecordRef; TimeSheetDetailId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a time registration entry, use a PATCH method to change it and then verify the changes // [GIVEN] A Time registration entry UserSetup.DeleteAll(); @@ -745,6 +781,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a purchase credit memo and a purchase cr memo line through a POST method and check if it was created // [GIVEN] A purchase credit memo LibraryPurchase.CreatePurchaseCreditMemo(PurchaseHeader); @@ -769,6 +806,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" PurchaseLine: Record "Purchase Line"; LineId: Guid; begin + Initialize(); // [SCENARIO] Create dimension lines in a purchase cr memo and purchase cr memo line and use a GET method to retrieve them // [GIVEN] a purchase cr memo with lines LibraryPurchase.CreatePurchaseCreditMemo(PurchaseHeader); @@ -792,6 +830,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a purchase credit memo and a purchase cr memo line, use a PATCH method to change it and then verify the changes // [GIVEN] A purchase credit memo LibraryPurchase.CreatePurchaseCreditMemo(PurchaseHeader); @@ -818,6 +857,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a purchase credit memo and a purchase cr memo line, use a DELETE method to remove it and then verify the deletion // [GIVEN] A purchase credit memo LibraryPurchase.CreatePurchaseCreditMemo(PurchaseHeader); @@ -851,6 +891,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" TargetURL: Text; DimensionSetID: Integer; begin + Initialize(); + // [GIVEN] 2 dimension json texts LibraryDimension.CreateDimension(Dimension); DimensionCode := Dimension.Code; @@ -928,6 +970,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Try to change the code of an existing dimension line LibraryGraphJournalLines.Initialize(); @@ -978,6 +1022,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" JournalName: Code[10]; JournalLineGUID: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line, use a DELETE method to remove it and then verify the deletion LibraryGraphJournalLines.Initialize(); @@ -1000,6 +1045,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales order and a sales order, use a DELETE method to remove it and then verify the deletion // [GIVEN] A sales order LibrarySales.CreateSalesOrder(SalesHeader); @@ -1028,6 +1074,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineId: Guid; CustomerNo: Code[20]; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales quote and sales quote line, use a DELETE method to remove it and then verify the deletion // [GIVEN] A sales quote LibrarySales.CreateCustomer(Customer); @@ -1056,6 +1103,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales credit memo and a sales cr memo line, use a DELETE method to remove it and then verify the deletion // [GIVEN] A sales credit memo LibrarySales.CreateSalesCreditMemo(SalesHeader); @@ -1082,6 +1130,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a sales invoice and a sales invoice line, use a DELETE method to remove it and then verify the deletion // [GIVEN] A sales invoice LibrarySales.CreateSalesInvoice(SalesHeader); @@ -1108,6 +1157,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a purchase invoice and a purchase invoice line, use a DELETE method to remove it and then verify the deletion LibraryPurchase.CreatePurchaseInvoice(PurchaseHeader); DocumentRecordRef.GetTable(PurchaseHeader); @@ -1133,6 +1183,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" LineRecordRef: RecordRef; LineId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a purchase order and a purchase order, use a DELETE method to remove it and then verify the deletion // [GIVEN] A purchase order LibraryPurchase.CreatePurchaseOrder(PurchaseHeader); @@ -1157,6 +1208,7 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" DocumentRecordRef: RecordRef; TimeSheetDetailId: Guid; begin + Initialize(); // [SCENARIO] Create a dimension line in a time registration entry, use a DELETE method to remove it and then verify the deletion // [GIVEN] A Time registration entry TimeSheetDetailId := CreateTimeSheet(); @@ -1179,6 +1231,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [GIVEN] a dimension line in the journal line LibraryDimension.CreateDimension(Dimension); DimensionValue.Reset(); @@ -1240,6 +1294,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [GIVEN] a dimension line in the journal line LibraryDimension.CreateDimension(Dimension); DimensionValue.Reset(); @@ -1296,6 +1352,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [GIVEN] a dimension with a value LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); @@ -1357,6 +1415,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [GIVEN] a dimension with a value LibraryDimension.CreateDimension(Dimension); LibraryDimension.CreateDimensionValue(DimensionValue, Dimension.Code); @@ -1406,6 +1466,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [GIVEN] 2 dimensions with dimension values LibraryDimension.CreateDimension(Dimension); DimensionCode[2] := Dimension.Code; @@ -1450,6 +1512,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [GIVEN] 2 dimensions with dimension values LibraryDimension.CreateDimension(Dimension); DimensionCode[2] := Dimension.Code; @@ -1501,6 +1565,8 @@ codeunit 139825 "APIV2 - Dim. Set Lines E2E" TargetURL: Text; DimensionSetID: Integer; begin + Initialize(); + // [GIVEN] 2 dimension json texts LibraryDimension.CreateDimension(Dimension); DimensionCode := Dimension.Code; diff --git a/src/Apps/W1/APIV2/test/src/APIV2DimensionsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2DimensionsE2E.Codeunit.al index 9b14ca531ea..a0c81c571cd 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2DimensionsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2DimensionsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139824 "APIV2 - Dimensions E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -20,9 +21,14 @@ codeunit 139824 "APIV2 - Dimensions E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; @@ -136,4 +142,3 @@ codeunit 139824 "APIV2 - Dimensions E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2DocumentAttachE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2DocumentAttachE2E.Codeunit.al index d38126db6a0..dc813383746 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2DocumentAttachE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2DocumentAttachE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139899 "APIV2 - Document Attach. E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -32,6 +33,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table LibrarySales.CreateCustomer(Customer); @@ -56,6 +59,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table LibrarySmallBusiness.CreateItem(Item); @@ -80,6 +85,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table LibraryHumanResources.CreateEmployee(Employee); @@ -104,6 +111,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table LibraryJob.CreateJob(Job); @@ -128,6 +137,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table LibrarySmallBusiness.CreateVendor(Vendor); @@ -152,6 +163,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); @@ -174,6 +187,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table CreateDraftSalesInvoice(DocumentRecordRef); @@ -197,6 +212,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table CreatePostedPurchaseInvoice(DocumentRecordRef, DocumentId); @@ -219,6 +236,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table CreateDraftPurchaseInvoice(DocumentRecordRef); @@ -241,6 +260,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table CreateSalesQuote(DocumentRecordRef); @@ -264,6 +285,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Document Attachment table CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); @@ -286,6 +309,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Document Attachment table CreateDraftSalesInvoice(DocumentRecordRef); @@ -308,6 +333,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Document Attachment table CreateDraftSalesOrder(DocumentRecordRef); @@ -330,6 +357,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve the Attachment record from the Attachment API. // [GIVEN] Attachment exists in the Document Attachment table CreateSalesQuote(DocumentRecordRef); @@ -352,6 +381,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table CreateDraftPurchaseOrder(DocumentRecordRef); @@ -379,6 +410,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ExpectedBase64Content: Text; ActualBase64Content: Text; begin + Initialize(); + // [SCENARIO] User can update linked attachment binary content through the Attachment API. // [GIVEN] A linked attachment exists LibrarySmallBusiness.CreateCustomer(Customer); @@ -407,6 +440,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" Customer: Record Customer; DocumentRecordRef: RecordRef; begin + Initialize(); + LibrarySmallBusiness.CreateCustomer(Customer); DocumentRecordRef.GetTable(Customer); TestCreateAttachment(DocumentRecordRef); @@ -418,6 +453,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" Vendor: Record Vendor; DocumentRecordRef: RecordRef; begin + Initialize(); + LibrarySmallBusiness.CreateVendor(Vendor); DocumentRecordRef.GetTable(Vendor); TestCreateAttachment(DocumentRecordRef); @@ -430,6 +467,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" DocumentId: Guid; DocumentType: Text; begin + Initialize(); + CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); DocumentType := GetDocumentType(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef, DocumentId, DocumentType); @@ -440,6 +479,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftSalesInvoice(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -449,6 +490,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftSalesOrder(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -460,6 +503,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" DocumentId: Guid; DocumentType: Text; begin + Initialize(); + CreatePostedPurchaseInvoice(DocumentRecordRef, DocumentId); DocumentType := GetDocumentType(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef, DocumentId, DocumentType); @@ -470,6 +515,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseInvoice(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -479,6 +526,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseOrder(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -530,6 +579,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateSalesQuote(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -540,6 +591,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" Vendor: Record Vendor; DocumentRecordRef: RecordRef; begin + Initialize(); + LibrarySmallBusiness.CreateVendor(Vendor); DocumentRecordRef.GetTable(Vendor); CreateAttachment(DocumentRecordRef); @@ -552,6 +605,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" Employee: Record Employee; DocumentRecordRef: RecordRef; begin + Initialize(); + LibraryHumanResources.CreateEmployee(Employee); DocumentRecordRef.GetTable(Employee); CreateAttachment(DocumentRecordRef); @@ -564,6 +619,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" Job: Record Job; DocumentRecordRef: RecordRef; begin + Initialize(); + LibraryJob.CreateJob(Job); DocumentRecordRef.GetTable(Job); CreateAttachment(DocumentRecordRef); @@ -576,6 +633,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedSalesInvoice(DocumentRecordRef, DocumentId); TestDeleteAttachment2(DocumentRecordRef); end; @@ -585,6 +644,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftSalesInvoice(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -595,6 +656,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedPurchaseInvoice(DocumentRecordRef, DocumentId); TestDeleteAttachment2(DocumentRecordRef); end; @@ -604,6 +667,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseInvoice(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -613,6 +678,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateSalesQuote(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -625,6 +692,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table CreateDraftPurchaseCreditMemo(DocumentRecordRef); @@ -648,6 +717,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can retrieve all records from the Attachments API. // [GIVEN] 2 Attachments in the Document Attachment table CreatePostedPurchaseCreditMemo(DocumentRecordRef, DocumentId); @@ -667,6 +738,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseCreditMemo(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef); end; @@ -678,6 +751,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" DocumentId: Guid; DocumentType: Text; begin + Initialize(); + CreatePostedPurchaseCreditMemo(DocumentRecordRef, DocumentId); DocumentType := GetDocumentType(DocumentRecordRef); TestCreateAttachment(DocumentRecordRef, DocumentId, DocumentType); @@ -688,6 +763,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" var DocumentRecordRef: RecordRef; begin + Initialize(); + CreateDraftPurchaseCreditMemo(DocumentRecordRef); TestDeleteAttachment(DocumentRecordRef); end; @@ -698,6 +775,8 @@ codeunit 139899 "APIV2 - Document Attach. E2E" DocumentRecordRef: RecordRef; DocumentId: Guid; begin + Initialize(); + CreatePostedPurchaseCreditMemo(DocumentRecordRef, DocumentId); TestDeleteAttachment2(DocumentRecordRef); end; @@ -1035,4 +1114,11 @@ codeunit 139899 "APIV2 - Document Attach. E2E" exit(StrSubstNo('%1.%2', Name, Extension)); exit(Name); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2EmployeesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2EmployeesE2E.Codeunit.al index 9dca78748ec..ca757d49767 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2EmployeesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2EmployeesE2E.Codeunit.al @@ -25,12 +25,17 @@ codeunit 139822 "APIV2 - Employees E2E" var LibraryApplicationArea: Codeunit "Library - Application Area"; begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryApplicationArea.EnableBasicHRSetup(); // Lazy Setup. if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryHumanResource.SetupEmployeeNumberSeries(); IsInitialized := true; @@ -223,4 +228,3 @@ codeunit 139822 "APIV2 - Employees E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2FALocationsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2FALocationsE2E.Codeunit.al index 9a23cb8f5c7..9f7071a3e4f 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2FALocationsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2FALocationsE2E.Codeunit.al @@ -21,9 +21,14 @@ codeunit 139906 "APIV2 - FA Locations E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2FixedAssetsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2FixedAssetsE2E.Codeunit.al index 3efd9d6a789..0a2ded0e7f1 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2FixedAssetsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2FixedAssetsE2E.Codeunit.al @@ -23,9 +23,14 @@ codeunit 139907 "APIV2 - Fixed Assets E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2GLEntriesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2GLEntriesE2E.Codeunit.al index bb7b691b29f..d642ac47f98 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2GLEntriesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2GLEntriesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139830 "APIV2 - GLEntries E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -24,10 +25,15 @@ codeunit 139830 "APIV2 - GLEntries E2E" LibraryERMCountryData: Codeunit "Library - ERM Country Data"; LibraryApplicationArea: Codeunit "Library - Application Area"; begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryApplicationArea.EnableFoundationSetup(); if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateVATPostingSetup(); LibraryERMCountryData.UpdateGeneralLedgerSetup(); @@ -161,5 +167,3 @@ codeunit 139830 "APIV2 - GLEntries E2E" - - diff --git a/src/Apps/W1/APIV2/test/src/APIV2GLSetupE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2GLSetupE2E.Codeunit.al index 187cb7f3af7..213af4575c7 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2GLSetupE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2GLSetupE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139860 "APIV2 - G/L Setup E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; var Assert: Codeunit "Assert"; @@ -13,6 +14,8 @@ codeunit 139860 "APIV2 - G/L Setup E2E" GeneralLedgerSetup: Record "General Ledger Setup"; Response, TargetURL : Text; begin + Initialize(); + GeneralLedgerSetup.Get(); TargetURL := LibraryGraphMgt.CreateTargetURL('', Page::"APIV2 - G/L Setup", ServiceNameTxt); LibraryGraphMgt.GetFromWebService(Response, TargetURL); @@ -60,4 +63,11 @@ codeunit 139860 "APIV2 - G/L Setup E2E" Assert.AreEqual(GeneralLedgerSetup."Shortcut Dimension 8 Code", PropertyJsonToken.AsValue().AsText(), 'Expected the same shortcutDimension8Code for generalLedgerSetup'); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } \ No newline at end of file diff --git a/src/Apps/W1/APIV2/test/src/APIV2GenProdPostGroupE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2GenProdPostGroupE2E.Codeunit.al index 6120bf37cdd..e594b1e6da8 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2GenProdPostGroupE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2GenProdPostGroupE2E.Codeunit.al @@ -1,12 +1,9 @@ codeunit 139856 "APIV2 - GenProdPostGroup E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; - trigger OnRun() - begin - end; - var ERMVATToolHelper: Codeunit "ERM VAT Tool - Helper"; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; @@ -21,6 +18,8 @@ codeunit 139856 "APIV2 - GenProdPostGroup E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [SCENARIO] Create a General Product Posting Group and use a GET method to retrieve it // [GIVEN] A Gen. Prod. Post. Group ERMVATToolHelper.CreateGenProdPostingGroup(GenProductPostingGroup, true); @@ -41,4 +40,11 @@ codeunit 139856 "APIV2 - GenProdPostGroup E2E" end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } \ No newline at end of file diff --git a/src/Apps/W1/APIV2/test/src/APIV2IncomeStatementE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2IncomeStatementE2E.Codeunit.al index 94109479bc6..49648b80327 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2IncomeStatementE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2IncomeStatementE2E.Codeunit.al @@ -62,9 +62,14 @@ codeunit 139816 "APIV2 - Income Statement E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := true; end; @@ -88,4 +93,3 @@ codeunit 139816 "APIV2 - Income Statement E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2InventoryPostGroupE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2InventoryPostGroupE2E.Codeunit.al index 3f357b613b8..7d3f5e05774 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2InventoryPostGroupE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2InventoryPostGroupE2E.Codeunit.al @@ -1,11 +1,8 @@ codeunit 139857 "APIV2 - InventoryPostGroup E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; - trigger OnRun() - begin - end; - var LibraryInventory: Codeunit "Library - Inventory"; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; @@ -21,6 +18,8 @@ codeunit 139857 "APIV2 - InventoryPostGroup E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [SCENARIO] Create an Inventory Posting Group and use a GET to retrieve it // [GIVEN] An Inventory Posting Group LibraryInventory.CreateInventoryPostingGroup(InventoryPostingGroup); @@ -40,4 +39,11 @@ codeunit 139857 "APIV2 - InventoryPostGroup E2E" 'Could not find created Inventory Posting Group on the response'); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } \ No newline at end of file diff --git a/src/Apps/W1/APIV2/test/src/APIV2ItemCategoriesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2ItemCategoriesE2E.Codeunit.al index 48a2175efe0..7e8a2532e28 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2ItemCategoriesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2ItemCategoriesE2E.Codeunit.al @@ -155,9 +155,14 @@ codeunit 139807 "APIV2 - Item Categories E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; end; @@ -231,4 +236,3 @@ codeunit 139807 "APIV2 - Item Categories E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2ItemVariantsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2ItemVariantsE2E.Codeunit.al index 2850134d790..064047b0f5a 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2ItemVariantsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2ItemVariantsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139839 "APIV2 - Item Variants E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -20,6 +21,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create an item variant through a POST method and check if it was created // [GIVEN] a JSON text with an item variant with itemId CreateItem(Item); @@ -44,6 +47,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Cannot create an Item Variant with non-existing itemId // [GIVEN] a JSON text with an item variant with non-existing itemId ItemId := CreateGuid(); @@ -65,6 +70,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create an item variant through a POST method and check if it was created // [GIVEN] a JSON text with an item variant with itemNumber CreateItem(Item); @@ -90,6 +97,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Cannot create an Item Variant with non-existing itemNumber // [GIVEN] a JSON text with an item variant with non-existing itemNumber ItemNo := LibraryUtility.GenerateRandomCode(ItemVariant.FieldNo(Code), Database::"Item Variant"); @@ -111,6 +120,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create an item variant through a POST method and check if it was created // [GIVEN] a JSON text with an item variant with itemNumber and itemId CreateItem(Item); @@ -136,6 +147,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Cannot create an Item Variant with mismatching itemNumber and itemId // [GIVEN] a JSON text with an item variant with mismatching itemNumber and itemId CreateItem(Item1); @@ -159,6 +172,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Cannot create an Item Variant if there is an item variant with same itemNumber and code // [GIVEN] a JSON text with an item variant with same itemNumber and code CreateItem(Item); @@ -181,6 +196,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Get a simple customer with a GET request to the service. // [GIVEN] An item variant exists in the system CreateItem(Item); @@ -206,6 +223,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create an item variant, use a PATCH method to change it and then verify the changes // [GIVEN] an item variant exists in the system CreateItem(Item); @@ -238,6 +257,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create an item variant, use a PATCH method to change it and then verify the changes // [GIVEN] an item variant exists in the system CreateItem(Item1); @@ -271,6 +292,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create an item variant, use a PATCH method to change it and then verify the changes // [GIVEN] an item variant exists in the system CreateItem(Item1); @@ -300,6 +323,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create an item variant, use a DELETE method to remove it and then verify the deletion // [GIVEN] an item variant in the system CreateItem(Item); @@ -326,6 +351,8 @@ codeunit 139839 "APIV2 - Item Variants E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Cannot delete an item variant in use // [GIVEN] an item variant in the system and used in a sales order line LibraryInventory.CreateItem(Item); @@ -440,4 +467,11 @@ codeunit 139839 "APIV2 - Item Variants E2E" exit(CopyStr('GRAPHITEM' + '00001', 1, 20)); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2ItemsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2ItemsE2E.Codeunit.al index 98f53fcb285..e26d64bb86d 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2ItemsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2ItemsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139800 "APIV2 - Items E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -30,9 +31,14 @@ codeunit 139800 "APIV2 - Items E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; @@ -936,8 +942,6 @@ codeunit 139800 "APIV2 - Items E2E" - - diff --git a/src/Apps/W1/APIV2/test/src/APIV2JobQueueEntriesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2JobQueueEntriesE2E.Codeunit.al index fd33be96961..82245a5b93e 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2JobQueueEntriesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2JobQueueEntriesE2E.Codeunit.al @@ -25,6 +25,8 @@ codeunit 139862 "APIV2JobQueueEntriesE2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO] Create 1 JobQueueEntry and use a GET method to retrieve it· // [GIVEN] Clean Job Queue Entries and create a new JobQueueEntry JobQueueEntry.DeleteAll(); @@ -51,6 +53,8 @@ codeunit 139862 "APIV2JobQueueEntriesE2E" ResponseText: Text; JobQueueEntryJSON: Text; begin + Initialize(); + // [SCENARIO] Create 1 JobQueueEntry and use a GET method to retrieve it. // [GIVEN] Clean Job Queue Entries and create a new JobQueueEntry and one corresponding JobQueueLogEntry JobQueueEntry.DeleteAll(); @@ -79,6 +83,8 @@ codeunit 139862 "APIV2JobQueueEntriesE2E" ResponseText: Text; JobQueueLogEntryJSON: Text; begin + Initialize(); + // [SCENARIO] Create 1 JobQueueEntry with 2 corresponding JobQueueLogEntries and use a GET method to retrieve it. // [GIVEN] Clean Job Queue Entries and create a new JobQueueEntry and 3 corresponding JobQueueLogEntries JobQueueEntry.DeleteAll(); @@ -105,6 +111,8 @@ codeunit 139862 "APIV2JobQueueEntriesE2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO] Create 1 JobQueueEntry with status error. Use an action to reschedule the JobQueueEntry // [GIVEN] Clean Job Queue Entries and create a new JobQueueEntry with status error JobQueueEntry.DeleteAll(); @@ -201,4 +209,11 @@ codeunit 139862 "APIV2JobQueueEntriesE2E" until (Index = LibraryGraphMgt.GetCollectionCountFromJSON(JobQueueLogEntryJSON)); Assert.AreEqual(Count, Index, 'The number of Job Queue Log Entries is wrong.'); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2JobQueueLogEntriesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2JobQueueLogEntriesE2E.Codeunit.al index 85e8931992b..2cdcbb60de4 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2JobQueueLogEntriesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2JobQueueLogEntriesE2E.Codeunit.al @@ -21,6 +21,8 @@ codeunit 139861 "APIV2JobQueueLogEntriesE2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO] Use a GET method to retrieve Job Queue Log Entries // [GIVEN] A new Job Queue Log Entry created JobQueueLogEntry.DeleteAll(); @@ -63,4 +65,11 @@ codeunit 139861 "APIV2JobQueueLogEntriesE2E" JobQueueLogEntry.Insert(); exit(JobQueueLogEntry); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2JournalsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2JournalsE2E.Codeunit.al index 5d6b35a0891..bce446d6a23 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2JournalsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2JournalsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139827 "APIV2 - Journals E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -32,9 +33,14 @@ codeunit 139827 "APIV2 - Journals E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; @@ -190,6 +196,8 @@ codeunit 139827 "APIV2 - Journals E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [GIVEN] A general journal batch with a general journal line BalAccountNo := LibraryERM.CreateGLAccountNoWithDirectPosting(); BalAccountType := GenJournalLine."Bal. Account Type"::"G/L Account"; @@ -272,4 +280,3 @@ codeunit 139827 "APIV2 - Journals E2E" GenJournalBatch.Modify(true); end; } - diff --git a/src/Apps/W1/APIV2/test/src/APIV2LocationsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2LocationsE2E.Codeunit.al index 667ae62e2f1..dc225782745 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2LocationsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2LocationsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139868 "APIV2 - Locations E2E" // version Test,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -24,9 +25,14 @@ codeunit 139868 "APIV2 - Locations E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2OpportunitiesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2OpportunitiesE2E.Codeunit.al index 50b6a4c45dd..40e1cb2ec3e 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2OpportunitiesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2OpportunitiesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139855 "APIV2 - Opportunities E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -31,6 +32,8 @@ codeunit 139855 "APIV2 - Opportunities E2E" ResponseText: Text; OpportunityId: Text; begin + Initialize(); + // [SCENARIO] Create an opportunity and use a GET method to retrieve them // [GIVEN] An opportunity ContactNo := LibraryMarketing.CreateCompanyContactNo(); @@ -60,6 +63,8 @@ codeunit 139855 "APIV2 - Opportunities E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO 184721] Create an opportunity through a POST method and check if it was created // [GIVEN] a JSON text with an Opportunity only with a Description property OpportunityJSON := CreateMinimalOpportunityJSON(OpportunityDescription); @@ -85,6 +90,8 @@ codeunit 139855 "APIV2 - Opportunities E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO 184721] Create an opportunity through a POST method and check if it was created // [GIVEN] a JSON text with an Opportunity only with a contact no ContactNo := LibraryMarketing.CreateCompanyContactNo(); @@ -125,6 +132,8 @@ codeunit 139855 "APIV2 - Opportunities E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO 184721] Create an opportunity through a POST method // [GIVEN] a JSON text with an Opportunity only with a contact number that does not exist ContactNo := 'wrongContNo'; @@ -146,6 +155,8 @@ codeunit 139855 "APIV2 - Opportunities E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO 184721] Create an opportunity through a POST method // [GIVEN] a JSON text with an Opportunity only with a salesperson number that does not exist SalespersonNo := 'wrongSPNo'; @@ -169,6 +180,8 @@ codeunit 139855 "APIV2 - Opportunities E2E" ResponseText: Text; OpportunityId: Guid; begin + Initialize(); + // [SCENARIO] Use a PATCH method to change the description of an opportunity // [GIVEN] An opportunity ContactNo := LibraryMarketing.CreateCompanyContactNo(); @@ -199,6 +212,8 @@ codeunit 139855 "APIV2 - Opportunities E2E" ResponseText: Text; OpportunityId: Guid; begin + Initialize(); + // [SCENARIO] Use a PATCH method to change the contact no of a Won opportunity // [GIVEN] An won opportunity CompanyContactNo := LibraryMarketing.CreateCompanyContactNo(); @@ -228,6 +243,8 @@ codeunit 139855 "APIV2 - Opportunities E2E" ResponseText: Text; OpportunityId: Guid; begin + Initialize(); + // [SCENARIO] Use a PATCH method to change the salesperson code of a Won opportunity // [GIVEN] An won opportunity SalesPersonCode := CreateSalesperson(SalespersonPurchaser); @@ -256,6 +273,8 @@ codeunit 139855 "APIV2 - Opportunities E2E" ResponseText: Text; OpportunityId: Guid; begin + Initialize(); + // [SCENARIO] Use a PATCH method to change the contact no of an opportunity in progress to a contact of a different company // [GIVEN] An won opportunity CompanyContactNo1 := LibraryMarketing.CreateCompanyContactNo(); @@ -408,4 +427,11 @@ codeunit 139855 "APIV2 - Opportunities E2E" Opportunity.SetRange(Description, DescriptionValue); Assert.IsFalse(Opportunity.IsEmpty(), 'Opportunity does not exist'); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2PDFDocumentE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PDFDocumentE2E.Codeunit.al index 63c5aabb741..f8603299edb 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PDFDocumentE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PDFDocumentE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139841 "APIV2 - PDF Document E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -26,6 +27,10 @@ codeunit 139841 "APIV2 - PDF Document E2E" var CompanyInformation: Record "Company Information"; begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + CompanyInformation.Get(); if CompanyInformation."Giro No." = '' then CompanyInformation."Giro No." := '1234567'; @@ -381,4 +386,3 @@ codeunit 139841 "APIV2 - PDF Document E2E" Commit(); end; } - diff --git a/src/Apps/W1/APIV2/test/src/APIV2PaymentMethodsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PaymentMethodsE2E.Codeunit.al index ca63c08260f..5358c09d5ef 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PaymentMethodsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PaymentMethodsE2E.Codeunit.al @@ -155,9 +155,14 @@ codeunit 139814 "APIV2 - Payment Methods E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; end; @@ -231,4 +236,3 @@ codeunit 139814 "APIV2 - Payment Methods E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2PaymentTermsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PaymentTermsE2E.Codeunit.al index 0e56cd7e8dc..fb872702d9d 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PaymentTermsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PaymentTermsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139804 "APIV2 - Payment Terms E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -19,9 +20,14 @@ codeunit 139804 "APIV2 - Payment Terms E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; @@ -97,4 +103,3 @@ codeunit 139804 "APIV2 - Payment Terms E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2PicturesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PicturesE2E.Codeunit.al index 317006420bd..09fd579e2ab 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PicturesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PicturesE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139842 "APIV2 - Pictures E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -29,9 +30,14 @@ codeunit 139842 "APIV2 - Pictures E2E" [Scope('OnPrem')] procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; end; @@ -44,6 +50,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobExpected: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Customer] // [SCENARIO] Get value picture from Customer Record @@ -68,6 +76,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Customer] // [SCENARIO] Get a picture metadata from Customer Record @@ -91,6 +101,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobResponse: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Customer] // [SCENARIO] Get value picture from Customer Record when no image exist @@ -112,6 +124,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Customer] // [SCENARIO] Get a picture metadata from Customer Record when no image is present @@ -137,6 +151,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Customer] // [SCENARIO] Set Picture on a customer without picture @@ -169,6 +185,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Customer] // [SCENARIO] Replace the Picture on a customer @@ -200,6 +218,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Customer] // [SCENARIO] Replace the Picture on a customer @@ -227,6 +247,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobExpected: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Vendor] // [SCENARIO] Get value picture from Vendor Record @@ -251,6 +273,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Vendor] // [SCENARIO] Get a picture metadata from Vendor Record @@ -274,6 +298,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobResponse: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Vendor] // [SCENARIO] Get value picture from Vendor Record when no image exist @@ -295,6 +321,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Vendor] // [SCENARIO] Get a picture metadata from Vendor Record when no image is present @@ -320,6 +348,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Vendor] // [SCENARIO] Set Picture on a Vendor without picture @@ -352,6 +382,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Vendor] // [SCENARIO] Replace the Picture on a Vendor @@ -383,6 +415,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Vendor] // [SCENARIO] Replace the Picture on a Vendor @@ -410,6 +444,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobExpected: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Employee] // [SCENARIO] Get value picture from Employee Record @@ -434,6 +470,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Employee] // [SCENARIO] Get a picture metadata from Employee Record @@ -457,6 +495,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobResponse: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Employee] // [SCENARIO] Get value picture from Employee Record when no image exist @@ -478,6 +518,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Employee] // [SCENARIO] Get a picture metadata from Employee Record when no image is present @@ -503,6 +545,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Employee] // [SCENARIO] Set Picture on a Employee without picture @@ -535,6 +579,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Employee] // [SCENARIO] Replace the Picture on a Employee @@ -566,6 +612,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Employee] // [SCENARIO] Replace the Picture on a Employee @@ -593,6 +641,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobExpected: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Item] // [SCENARIO] Get value picture from Item Record @@ -617,6 +667,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Item] // [SCENARIO] Get a picture metadata from Item Record @@ -640,6 +692,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobResponse: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Item] // [SCENARIO] Get value picture from Item Record when no image exist @@ -661,6 +715,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Item] // [SCENARIO] Get a picture metadata from Item Record when no image is present @@ -686,6 +742,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Item] // [SCENARIO] Set Picture on a Item without picture @@ -718,6 +776,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Item] // [SCENARIO] Replace the Picture on a Item @@ -749,6 +809,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Item] // [SCENARIO] Replace the Picture on a Item @@ -776,6 +838,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobExpected: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Contact] // [SCENARIO] Get value picture from Contact Record @@ -800,6 +864,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Contact] // [SCENARIO] Get a picture metadata from Contact Record @@ -823,6 +889,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TempBlobResponse: Codeunit "Temp Blob"; TargetURL: Text; begin + Initialize(); + // [FEATURE] [Contact] // [SCENARIO] Get value picture from Contact Record when no image exist @@ -844,6 +912,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Contact] // [SCENARIO] Get a picture metadata from Contact Record when no image is present @@ -869,6 +939,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Contact] // [SCENARIO] Set Picture on a contact without picture @@ -901,6 +973,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Contact] // [SCENARIO] Replace the Picture on a contact @@ -932,6 +1006,8 @@ codeunit 139842 "APIV2 - Pictures E2E" TargetURL: Text; Response: Text; begin + Initialize(); + // [FEATURE] [Contact] // [SCENARIO] Replace the Picture on a contact @@ -1102,4 +1178,3 @@ codeunit 139842 "APIV2 - Pictures E2E" end; } - diff --git a/src/Apps/W1/APIV2/test/src/APIV2PstdApprovalEntriesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PstdApprovalEntriesE2E.Codeunit.al index 8db85c18246..838eaa29477 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PstdApprovalEntriesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PstdApprovalEntriesE2E.Codeunit.al @@ -21,6 +21,8 @@ codeunit 139919 "APIV2 PstdApprovalEntries E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO] Check that posted approval entries can be retrieved via API // [GIVEN] a Sales order exists @@ -60,4 +62,10 @@ codeunit 139919 "APIV2 PstdApprovalEntries E2E" PostedApprovalEntry.Insert(); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } \ No newline at end of file diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchCrMLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchCrMLinesE2E.Codeunit.al index 71212c1efab..6d13e266eb0 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchCrMLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchCrMLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -30,6 +31,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Call GET on the lines without providing a parent Credit Memo ID. // [GIVEN] the credit memo API exposedSetAutoCalcFields @@ -56,6 +59,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" LineNo: Integer; SequenceValue: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Line of a credit memo // [GIVEN] a credit memo with a line.SetAutoCalcFields CreditMemoId := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -86,6 +91,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" LineNo1: Text; LineNo2: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Lines of a unposted Credit Memo // [GIVEN] An credit memo with lines.SetAutoCalcFields CreditMemoID := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -115,6 +122,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" LineNo1: Text; LineNo2: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Lines of a credit memo // [GIVEN] a credit memo with lines.SetAutoCalcFields CreditMemoId := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -144,6 +153,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" LineNo1: Text; LineNo2: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Lines of a posted Credit Memo // [GIVEN] A posted credit memo with lines.SetAutoCalcFields CreditMemoID := CreatePostedPurchaseCreditMemoWithLines(PurchCrMemoHdr); @@ -172,6 +183,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoID: Text; LineNo: Integer; begin + Initialize(); + // [SCENARIO] POST a new line to an unposted Credit Memo // [GIVEN] An existing unposted credit memo and a valid JSON describing the new credit memo lineSetAutoCalcFields CreditMemoID := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -203,6 +216,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoID: Text; LineNo: Integer; begin + Initialize(); + // [SCENARIO] POST a new line to an unposted Credit Memo with a sequence number // [GIVEN] An existing unposted credit memo and a valid JSON describing the new credit memo lineSetAutoCalcFields CreditMemoID := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -241,6 +256,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" PurchaseQuantity: Integer; PurchaseQuantityFromJSON: Text; begin + Initialize(); + // [SCENARIO] PATCH a line of an unposted Credit Memo // [GIVEN] An unposted credit memo with lines and a valid JSON describing the fields that we want to changeSetAutoCalcFields CreditMemoID := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -278,6 +295,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoId: Text; NewSequence: Integer; begin + Initialize(); + // [SCENARIO] PATCH a line of a credit memo will fail if sequence is modified // [GIVEN] A credit memo with lines and a valid JSON describing the fields that we want to changeSetAutoCalcFields CreditMemoId := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -318,6 +337,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoID: Text; LineNo: Integer; begin + Initialize(); + // [SCENARIO] DELETE a line from an unposted Credit Memo // [GIVEN] An unposted credit memo with linesSetAutoCalcFields CreditMemoID := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -348,6 +369,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoID: Text; LineNo: Integer; begin + Initialize(); + // [SCENARIO] Call DELETE on a line of a posted Credit Memo // [GIVEN] A posted credit memo with linesSetAutoCalcFields CreditMemoID := CreatePostedPurchaseCreditMemoWithLines(PurchCrMemoHdr); @@ -384,6 +407,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" ItemNo: Code[20]; VendorNo: Code[20]; begin + Initialize(); + // [SCENARIO] Create an credit memo both through the client UI and through the API and compare their final values. // [GIVEN] An unposted credit memo and a JSON describing the line we want to create LibraryPurchase.CreateVendor(Vendor); @@ -422,6 +447,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" ResponseText: Text; LinesJSON: Text; begin + Initialize(); + // [SCENARIO] Getting a line through API lists all possible types // [GIVEN] An credit memo with lines of different typesSetAutoCalcFields CreateCreditMemoWithDifferentLineTypes(PurchaseHeader, ExpectedNumberOfLines); @@ -447,6 +474,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" ResponseText: Text; CreditMemoLineJSON: Text; begin + Initialize(); + // [SCENARIO] Posting a line with description only will get a type item // [GIVEN] A post request with description onlySetAutoCalcFields CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -482,6 +511,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" ResponseText: Text; CreditMemoLineJSON: Text; begin + Initialize(); + // [FEATURE] [Comment] // [SCENARIO] Posting a line with Type Comment and description will make a comment line // [GIVEN] A post request with type and descriptionSetAutoCalcFields @@ -520,6 +551,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoLineJSON: Text; CreditMemoID: Text; begin + Initialize(); + // [SCENARIO] PATCH a Type on a line of an unposted Credit Memo // [GIVEN] An unposted credit memo with lines and a valid JSON describing the fields that we want to changeSetAutoCalcFields CreditMemoID := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -551,6 +584,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoLineJSON: Text; CreditMemoLineID: Text; begin + Initialize(); + // [SCENARIO] PATCH a Type on a line of an unposted Credit Memo // [GIVEN] An unposted credit memo with lines and a valid JSON describing the fields that we want to changeSetAutoCalcFields CreateCreditMemoWithDifferentLineTypes(PurchaseHeader, ExpectedNumberOfLines); @@ -588,6 +623,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoLineJSON: Text; CreditMemoID: Text; begin + Initialize(); + // [SCENARIO] PATCH a Type on a line of an unposted Credit Memo // [GIVEN] An unposted credit memo with lines and a valid JSON describing the fields that we want to changeSetAutoCalcFields CreditMemoID := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -622,6 +659,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoID: Text; LineNo: Integer; begin + Initialize(); + // [SCENARIO] POST a new line to an unposted Credit Memo with item variant // [GIVEN] An existing unposted credit memo and a valid JSON describing the new credit memo line with item variantSetAutoCalcFields CreditMemoID := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -658,6 +697,8 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" CreditMemoLineJSON: Text; CreditMemoID: Text; begin + Initialize(); + // [SCENARIO] POST a new line to an unposted Credit Memo with wrong item variant // [GIVEN] An existing unposted credit memo and a valid JSON describing the new credit memo line with item variantSetAutoCalcFields CreditMemoID := CreatePurchaseCreditMemoWithLines(PurchaseHeader); @@ -950,4 +991,11 @@ codeunit 139874 "APIV2 - Purch. Cr.M. Lines E2E" PurchaseLineComment.Description := 'Thank you for your business!'; PurchaseLineComment.Modify(); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchCrMemosE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchCrMemosE2E.Codeunit.al index 99bf5468337..ef529ca543e 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchCrMemosE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchCrMemosE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -39,6 +40,8 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create posted and unposted purchase credit memos and use a GET method to retrieve them // [GIVEN] 2 credit memos, one posted and one unposted CreatePurchaseCreditMemos(CreditMemoNo1, CreditMemoNo2); @@ -71,8 +74,11 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" TargetURL: Text; CreditMemo: Text; begin + Initialize(); + // [SCENARIO] Create posted and unposted Purchase credit memos and use HTTP POST to delete them // [GIVEN] 2 credit memos, one posted and one unposted + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryPurchase.CreateVendorWithAddress(BuyFromVendor); LibraryPurchase.CreateVendorWithAddress(PayToVendor); VendorNo := BuyFromVendor."No."; @@ -115,6 +121,8 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" CreditMemoJSON: Text; CurrencyCode: Code[10]; begin + Initialize(); + // [SCENARIO] Create posted and unposted with specific currency set and use HTTP POST to create them // [GIVEN] an CreditMemo with a non-LCY currencyCode set @@ -156,6 +164,8 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" CreditMemoJSON: Text; VendorCreditMemoNumber: Text; begin + Initialize(); + // [SCENARIO] Create posted and unposted with specific vendor credit memo number set and use HTTP POST to create them // [GIVEN] A credit memo with vendor credit memo number set @@ -186,18 +196,24 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" [Test] procedure TestModifyCreditMemos() begin + Initialize(); + TestMultipleModifyCreditMemos(false, false); end; [Test] procedure TestEmptyModifyCreditMemos() begin + Initialize(); + TestMultipleModifyCreditMemos(true, false); end; [Test] procedure TestPartialModifyCreditMemos() begin + Initialize(); + TestMultipleModifyCreditMemos(false, true); end; @@ -274,6 +290,8 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" CreditMemoNo: Text; CreditMemoID: Text; begin + Initialize(); + // [SCENARIO] Create unposted purchase credit memo and use HTTP DELETE to delete it // [GIVEN] An unposted credit memo CreateDraftPurchaseCreditMemo(PurchaseHeader); @@ -305,9 +323,12 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" CreditMemoPostingDate: Date; CreditMemoJSON: Text; begin + Initialize(); + // [SCENARIO] Create an credit memo both through the client UI and through the API // [SCENARIO] and compare them. They should be the same and have the same fields autocompleted wherever needed. // [GIVEN] An unposted credit memo + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryGraphDocumentTools.InitializeUIPage(); LibraryPurchase.CreateVendor(BuyFromVendor); @@ -343,6 +364,8 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" ResponseText: Text; CreditMemoID: Text; begin + Initialize(); + // [SCENARIO 184721] Create Credit Memo, use a PATCH method to change it and then verify the changes LibraryPurchase.CreateVendorWithAddress(Vendor); @@ -389,6 +412,8 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" ResponseText: Text; CreditMemoID: Text; begin + Initialize(); + // [SCENARIO 184721] Clearing manually set discount // [GIVEN] an item with unit price and unit cost @@ -439,6 +464,8 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can post a purchase credit memo through the API. LibraryERMCountryData.UpdatePurchasesPayablesSetup(); // [GIVEN] Draft purchase credit memo exists @@ -472,6 +499,8 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can cancel a posted purchase credit memo through API. // [GIVEN] Non-corrective purchase credit memo exists @@ -500,6 +529,8 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can cancel a posted purchase credit memo through API. // [GIVEN] Corrective purchase credit memo exists @@ -714,5 +745,11 @@ codeunit 139865 "APIV2 - Purch. Cr. Memos E2E" Assert.IsTrue(PurchCrMemoEntityBuffer.FindFirst(), CannotFindPostedCreditMemoErr); Assert.AreEqual(Status, PurchCrMemoEntityBuffer.Status, CreditMemoStatusErr); end; -} + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; +} diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchOrderLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchOrderLinesE2E.Codeunit.al index 10c1f29cd26..15993ed317a 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchOrderLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchOrderLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139852 "APIV2 - Purch. Order Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -30,9 +31,14 @@ codeunit 139852 "APIV2 - Purch. Order Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := true; diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchQuotesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchQuotesE2E.Codeunit.al index fff9ebbec3e..ff9a8586045 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchQuotesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchQuotesE2E.Codeunit.al @@ -24,6 +24,8 @@ codeunit 139922 "APIV2 - Purch. Quotes E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a purchase quote and use GET to retrieve it // [GIVEN] A purchase quote LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Quote, ''); @@ -44,6 +46,8 @@ codeunit 139922 "APIV2 - Purch. Quotes E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a purchase quote and GET it by SystemId // [GIVEN] A purchase quote LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Quote, ''); @@ -66,6 +70,8 @@ codeunit 139922 "APIV2 - Purch. Quotes E2E" TargetURL: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase quote with $expand=dimensionSetLines // [GIVEN] A purchase quote PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::Quote); @@ -92,6 +98,8 @@ codeunit 139922 "APIV2 - Purch. Quotes E2E" TargetURL: Text; AttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase quote with $expand=attachments // [GIVEN] A purchase quote PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::Quote); @@ -118,6 +126,8 @@ codeunit 139922 "APIV2 - Purch. Quotes E2E" TargetURL: Text; DocumentAttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase quote with $expand=documentAttachments // [GIVEN] A purchase quote PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::Quote); @@ -144,6 +154,8 @@ codeunit 139922 "APIV2 - Purch. Quotes E2E" TargetURL: Text; PdfDocumentValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase quote with $expand=pdfDocument // [GIVEN] A purchase quote PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::Quote); @@ -170,6 +182,8 @@ codeunit 139922 "APIV2 - Purch. Quotes E2E" TargetURL: Text; LinesValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase quote with $expand=purchaseQuoteLines // [GIVEN] A purchase quote PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::Quote); @@ -194,4 +208,10 @@ codeunit 139922 "APIV2 - Purch. Quotes E2E" exit(TargetURL + '&$expand=' + ExpandValue); exit(TargetURL + '?$expand=' + ExpandValue); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchRcptLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchRcptLinesE2E.Codeunit.al index c3c96805fb3..fdff569f0f9 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchRcptLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchRcptLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139850 "APIV2 - Purch. Rcpt. Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -29,6 +30,8 @@ codeunit 139850 "APIV2 - Purch. Rcpt. Lines E2E" LineNo: Integer; SequenceValue: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Line of a purchase receipt // [GIVEN] A receipt with a line. LibraryPurchase.CreatePurchaseOrder(PurchaseHeader); @@ -62,6 +65,8 @@ codeunit 139850 "APIV2 - Purch. Rcpt. Lines E2E" LineNo1: Text; LineNo2: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Lines of a Purchase Receipt // [GIVEN] A purchase receipt with lines. CreatePurchaseOrderMultipleLines(PurchaseHeader); @@ -103,6 +108,8 @@ codeunit 139850 "APIV2 - Purch. Rcpt. Lines E2E" LineNo1: Text; LineNo2: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Lines of a purchase receipt // [GIVEN] A purchase receipt with lines. CreatePurchaseOrderMultipleLines(PurchaseHeader); @@ -136,6 +143,8 @@ codeunit 139850 "APIV2 - Purch. Rcpt. Lines E2E" LineIdTxt: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Line of a purchase receipt and expand the dimension set lines // [GIVEN] A receipt with a line. PurchRcptHeader.FindFirst(); @@ -250,4 +259,11 @@ codeunit 139850 "APIV2 - Purch. Rcpt. Lines E2E" exit(TargetURL); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchRetOrdersE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchRetOrdersE2E.Codeunit.al index a80fc37128d..fb659365ef9 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchRetOrdersE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchRetOrdersE2E.Codeunit.al @@ -24,6 +24,8 @@ codeunit 139923 "APIV2 - Purch. Ret. Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a purchase return order and use GET to retrieve it // [GIVEN] A purchase return order LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::"Return Order", ''); @@ -44,6 +46,8 @@ codeunit 139923 "APIV2 - Purch. Ret. Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a purchase return order and GET it by SystemId // [GIVEN] A purchase return order LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::"Return Order", ''); @@ -66,6 +70,8 @@ codeunit 139923 "APIV2 - Purch. Ret. Orders E2E" TargetURL: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase return order with $expand=dimensionSetLines // [GIVEN] A purchase return order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Return Order"); @@ -92,6 +98,8 @@ codeunit 139923 "APIV2 - Purch. Ret. Orders E2E" TargetURL: Text; AttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase return order with $expand=attachments // [GIVEN] A purchase return order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Return Order"); @@ -118,6 +126,8 @@ codeunit 139923 "APIV2 - Purch. Ret. Orders E2E" TargetURL: Text; DocumentAttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase return order with $expand=documentAttachments // [GIVEN] A purchase return order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Return Order"); @@ -144,6 +154,8 @@ codeunit 139923 "APIV2 - Purch. Ret. Orders E2E" TargetURL: Text; PdfDocumentValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase return order with $expand=pdfDocument // [GIVEN] A purchase return order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Return Order"); @@ -170,6 +182,8 @@ codeunit 139923 "APIV2 - Purch. Ret. Orders E2E" TargetURL: Text; LinesValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase return order with $expand=purchaseReturnOrderLines // [GIVEN] A purchase return order PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::"Return Order"); @@ -194,4 +208,10 @@ codeunit 139923 "APIV2 - Purch. Ret. Orders E2E" exit(TargetURL + '&$expand=' + ExpandValue); exit(TargetURL + '?$expand=' + ExpandValue); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchRetShptsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchRetShptsE2E.Codeunit.al index 7df56e4842f..5af2df6ab53 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchRetShptsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchRetShptsE2E.Codeunit.al @@ -24,6 +24,8 @@ codeunit 139928 "APIV2 - Purch. Ret. Shpts. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Post a purchase return order and use GET to retrieve the resulting return shipment // [GIVEN] A posted purchase return shipment EnsurePurchaseReturnShipment(ReturnShipmentHeader); @@ -44,6 +46,8 @@ codeunit 139928 "APIV2 - Purch. Ret. Shpts. E2E" TargetURL: Text; AttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase return shipment with $expand=attachments // [GIVEN] A posted purchase return shipment EnsurePurchaseReturnShipment(ReturnShipmentHeader); @@ -66,6 +70,8 @@ codeunit 139928 "APIV2 - Purch. Ret. Shpts. E2E" TargetURL: Text; DocumentAttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase return shipment with $expand=documentAttachments // [GIVEN] A posted purchase return shipment EnsurePurchaseReturnShipment(ReturnShipmentHeader); @@ -88,6 +94,8 @@ codeunit 139928 "APIV2 - Purch. Ret. Shpts. E2E" TargetURL: Text; PdfDocumentValue: Text; begin + Initialize(); + // [SCENARIO] GET a purchase return shipment with $expand=pdfDocument // [GIVEN] A posted purchase return shipment EnsurePurchaseReturnShipment(ReturnShipmentHeader); @@ -121,4 +129,10 @@ codeunit 139928 "APIV2 - Purch. Ret. Shpts. E2E" exit(TargetURL + '&$expand=' + ExpandValue); exit(TargetURL + '?$expand=' + ExpandValue); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchaseInvLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchaseInvLinesE2E.Codeunit.al index 0dbd34f7443..c4a7bdfab0a 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchaseInvLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchaseInvLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139838 "APIV2 - Purchase Inv Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -30,9 +31,14 @@ codeunit 139838 "APIV2 - Purchase Inv Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); LibraryERMCountryData.CreateGeneralPostingSetupData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); @@ -1145,6 +1151,5 @@ codeunit 139838 "APIV2 - Purchase Inv Lines E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchaseInvoicesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchaseInvoicesE2E.Codeunit.al index 2477d02b2ad..d3fbc749306 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchaseInvoicesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchaseInvoicesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139829 "APIV2 - Purchase Invoices E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -30,6 +31,10 @@ codeunit 139829 "APIV2 - Purchase Invoices E2E" local procedure Initialize() begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + + LibraryGraphMgt.SetLicenseSafeWorkDate(); end; [Test] @@ -75,6 +80,8 @@ codeunit 139829 "APIV2 - Purchase Invoices E2E" OrderIdValue: Text; OrderNoValue: Text; begin + Initialize(); + // [SCENARIO] Create a Purchase Invoice from a Purchase Order and use GET method to retrieve them and check the orderId and orderNumber // [GIVEN] A purchase invoice created by posting a purchase order LibraryPurchase.CreatePurchaseOrder(PurchaseHeader); @@ -444,6 +451,8 @@ codeunit 139829 "APIV2 - Purchase Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can map systemId with Draft Invoice SystemId // [GIVEN] Posted purchase invoice exists diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchaseOrdersE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchaseOrdersE2E.Codeunit.al index 1b799612203..d074fb583c0 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchaseOrdersE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchaseOrdersE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139851 "APIV2 - Purchase Orders E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -31,7 +32,10 @@ codeunit 139851 "APIV2 - Purchase Orders E2E" local procedure Initialize() begin - WorkDate := Today(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + + LibraryGraphMgt.SetLicenseSafeWorkDate(); end; [Test] @@ -92,8 +96,8 @@ codeunit 139851 "APIV2 - Purchase Orders E2E" ShipToVendor.Modify(true); Commit(); VendorNo := BuyFromVendor."No."; - OrderDate := Today(); - PostingDate := Today(); + OrderDate := WorkDate(); + PostingDate := WorkDate(); // [GIVEN] a JSON text with an order that contains the vendor and an address OrderJSON := CreateOrderJSONWithAddress(BuyFromVendor, PayToVendor, ShipToVendor, OrderDate, PostingDate); @@ -143,8 +147,8 @@ codeunit 139851 "APIV2 - Purchase Orders E2E" LibraryPurchase.CreateVendorWithAddress(BuyFromVendor); LibraryPurchase.CreateVendorWithAddress(PayToVendor); VendorNo := BuyFromVendor."No."; - OrderDate := Today(); - PostingDate := Today(); + OrderDate := WorkDate(); + PostingDate := WorkDate(); // [GIVEN] a JSON text with an order that contains the vendor and an address OrderJSON := CreateOrderJSONWithoutShipTo(BuyFromVendor, PayToVendor, OrderDate, PostingDate); @@ -402,8 +406,8 @@ codeunit 139851 "APIV2 - Purchase Orders E2E" // [GIVEN] a customer LibraryPurchase.CreateVendor(Vendor); VendorNo := Vendor."No."; - OrderDate := Today(); - PostingDate := Today(); + OrderDate := WorkDate(); + PostingDate := WorkDate(); // [GIVEN] a json describing our new order OrderJSON := CreateOrderJSONWithAddress(Vendor, Vendor, Vendor, OrderDate, PostingDate); @@ -603,6 +607,8 @@ codeunit 139851 "APIV2 - Purchase Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can recieve and invoice a purchase order through the API. // [GIVEN] Create vendors and a Purchase order with lines @@ -667,6 +673,7 @@ codeunit 139851 "APIV2 - Purchase Orders E2E" PurchaseOrder."Buy-from Vendor No.".SetValue(Vendor."No."); PurchaseOrder."Document Date".SetValue(DocumentDate); PurchaseOrder."Posting Date".SetValue(PostingDate); + PurchaseOrder."Order Date".SetValue(DocumentDate); end; local procedure CheckShippingDetailsNotEmpty(var PurchaseHeader: Record "Purchase Header") diff --git a/src/Apps/W1/APIV2/test/src/APIV2PurchaseReceiptsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2PurchaseReceiptsE2E.Codeunit.al index da2b96c946c..9e0f0eb4f20 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2PurchaseReceiptsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2PurchaseReceiptsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139849 "APIV2 - Purchase Receipts E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -26,6 +27,8 @@ codeunit 139849 "APIV2 - Purchase Receipts E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create 2 purchase receipts (post sales order) and use a GET method to retrieve them // [GIVEN] 2 posted purchase receipts LibraryPurchase.CreatePurchaseOrder(PurchaseHeader); @@ -56,6 +59,8 @@ codeunit 139849 "APIV2 - Purchase Receipts E2E" ReceiptIdTxt: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] Call GET on purchase receipt and expand the dimension set lines // [GIVEN] A purchase receipt. @@ -106,4 +111,11 @@ codeunit 139849 "APIV2 - Purchase Receipts E2E" exit(TargetURL); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2RetEarningsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2RetEarningsE2E.Codeunit.al index 771bc75dd2f..2e013840315 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2RetEarningsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2RetEarningsE2E.Codeunit.al @@ -62,9 +62,14 @@ codeunit 139821 "APIV2 - Ret. Earnings E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := true; end; @@ -93,4 +98,3 @@ codeunit 139821 "APIV2 - Ret. Earnings E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesCrMemoLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesCrMemoLinesE2E.Codeunit.al index 203a1e04eb3..97f5259ebc3 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesCrMemoLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesCrMemoLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139837 "APIV2 - Sales CrMemo Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -30,9 +31,14 @@ codeunit 139837 "APIV2 - Sales CrMemo Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibrarySales.SetStockoutWarning(false); LibraryApplicationArea.EnableFoundationSetup(); @@ -1413,8 +1419,6 @@ codeunit 139837 "APIV2 - Sales CrMemo Lines E2E" - - diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesCreditMemosE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesCreditMemosE2E.Codeunit.al index 91631a22534..e37ba185768 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesCreditMemosE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesCreditMemosE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -56,6 +57,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create posted and unposted sales credit memos and use a GET method to retrieve them // [GIVEN] 2 credit memos, one posted and one unposted CreateSalesCreditMemos(CreditMemoNo1, CreditMemoNo2); @@ -88,9 +91,12 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" TargetURL: Text; CreditMemo: Text; begin + Initialize(); + // [SCENARIO] Create posted and unposted Sales credit memos and use HTTP POST to delete them // [GIVEN] 2 credit memos, one posted and one unposted + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibrarySales.CreateCustomerWithAddress(SellToCustomer); LibrarySales.CreateCustomerWithAddress(BillToCustomer); CustomerNo := SellToCustomer."No."; @@ -133,6 +139,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" CreditMemoJSON: Text; CurrencyCode: Code[10]; begin + Initialize(); + // [SCENARIO] Create posted and unposted with specific currency set and use HTTP POST to create them // [GIVEN] an CreditMemo with a non-LCY currencyCode set @@ -165,18 +173,24 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" [Test] procedure TestModifyCreditMemos() begin + Initialize(); + TestMultipleModifyCreditMemos(false, false); end; [Test] procedure TestEmptyModifyCreditMemos() begin + Initialize(); + TestMultipleModifyCreditMemos(true, false); end; [Test] procedure TestPartialModifyCreditMemos() begin + Initialize(); + TestMultipleModifyCreditMemos(false, true); end; @@ -252,6 +266,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" CreditMemoNo: Text; CreditMemoID: Text; begin + Initialize(); + // [SCENARIO] Create unposted sales credit memo and use HTTP DELETE to delete it // [GIVEN] An unposted credit memo CreateDraftSalesCreditMemo(SalesHeader); @@ -283,9 +299,12 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" CreditMemoPostingDate: Date; CreditMemoJSON: Text; begin + Initialize(); + // [SCENARIO] Create an credit memo both through the client UI and through the API // [SCENARIO] and compare them. They should be the same and have the same fields autocompleted wherever needed. // [GIVEN] An unposted credit memo + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryGraphDocumentTools.InitializeUIPage(); LibrarySales.CreateCustomer(SellToCustomer); @@ -316,6 +335,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" TargetURL: Text; DiscountPct: Decimal; begin + Initialize(); + // [SCENARIO] When an credit memo is created,the GET Method should update the credit memo and assign a total // [GIVEN] 2 credit memos, one posted and one unposted without totals assigned LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending( @@ -348,6 +369,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" DiscountAmt: Decimal; InvDiscAmount: Decimal; begin + Initialize(); + // [SCENARIO] When an credit memo is created, the GET Method should update the credit memo and assign a total // [GIVEN] 2 credit memos, one posted and one unposted with discount amount that should be redistributed LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending( @@ -387,6 +410,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; CreditMemoID: Text; begin + Initialize(); + // [SCENARIO 184721] Create Credit Memo, use a PATCH method to change it and then verify the changes LibrarySales.CreateCustomerWithAddress(Customer); @@ -433,6 +458,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; CreditMemoID: Text; begin + Initialize(); + // [SCENARIO 184721] Clearing manually set discount // [GIVEN] an item with unit price and unit cost @@ -488,6 +515,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" PostedCreditMemoEmailAddress: Text; PostedCreditMemoEmailSubject: Text; begin + Initialize(); + // [SCENARIO] User can post a sales credit memo through the API. // [GIVEN] Draft sales credit memo exists @@ -535,6 +564,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can post and send a sales credit memo through the API. InitializeForSending(); @@ -573,6 +604,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can cancel a posted sales credit memo through API. // [GIVEN] Non-corrective sales credit memo exists @@ -601,6 +634,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can cancel a posted sales credit memo through API. // [GIVEN] Corrective sales credit memo exists @@ -633,6 +668,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can cancel a posted sales credit memo through API. InitializeForSending(); @@ -669,6 +706,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can send a posted sales credit memo through the API. InitializeForSending(); @@ -701,6 +740,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Sending a draft sales credit memo through the API throws an error InitializeForSending(); @@ -730,6 +771,8 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can send a draft sales credit memo through the API. InitializeForSending(); @@ -1043,5 +1086,11 @@ codeunit 139828 "APIV2 - Sales Credit Memos E2E" while JobQueueEntry.FindJobQueueEntry(JobQueueEntry."Object Type to Run"::Codeunit, CodeunitID) do JobQueueEntry.Cancel(); end; -} + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; +} diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesInvLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesInvLinesE2E.Codeunit.al index 3a88184d347..395be869da7 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesInvLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesInvLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139834 "APIV2 - Sales Inv. Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -31,9 +32,14 @@ codeunit 139834 "APIV2 - Sales Inv. Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibrarySales.SetStockoutWarning(false); LibraryApplicationArea.EnableFoundationSetup(); diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesInvoicesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesInvoicesE2E.Codeunit.al index 9438dd8d7fc..d3f4600a9e6 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesInvoicesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesInvoicesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -70,6 +71,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO 184721] Create posted and unposted Sales invoices and use a GET method to retrieve them // [GIVEN] 2 invoices, one posted and one unposted CreateSalesInvoices(InvoiceID1, InvoiceID2); @@ -102,6 +105,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" OrderIdValue: Text; OrderNoValue: Text; begin + Initialize(); + // [SCENARIO] Create a Sales Invoice from a Sales Order and use GET method to retrieve them and check the orderId and orderNumber // [GIVEN] A sales invoice created by posting a sales order LibrarySales.CreateSalesOrder(SalesHeader); @@ -145,9 +150,12 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" TargetURL: Text; InvoiceJSON: Text; begin + Initialize(); + // [SCENARIO 184721] Create posted and unposted Sales invoices and use HTTP POST to delete them // [GIVEN] 2 invoices, one posted and one unposted + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibrarySales.CreateCustomer(SellToCustomer); LibrarySales.CreateCustomer(BillToCustomer); LibrarySales.CreateCustomer(ShipToCustomer); @@ -195,6 +203,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" InvoiceJSON: Text; CurrencyCode: Code[10]; begin + Initialize(); + // [SCENARIO 184721] Create posted and unposted with specific currency set and use HTTP POST to create them // [GIVEN] an Invoice with a non-LCY currencyCode set @@ -242,6 +252,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" Email: Text; CurrencyCode: Code[10]; begin + Initialize(); + // [SCENARIO 285872] Create posted and unposted with specific email set and use HTTP POST to create them Email := 'test@microsoft.com'; // [GIVEN] an Customer with no email set @@ -293,8 +305,12 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" TargetURL: Text; InvoiceJSON: Text; begin + Initialize(); + // [SCENARIO 184721] Create unposted with specific document and due date set and use HTTP POST to create them + LibraryGraphMgt.SetLicenseSafeWorkDate(); + // [GIVEN] an Invoice with a document and due date set LibrarySales.CreateCustomer(Customer); CustomerNo := Customer."No."; @@ -333,18 +349,24 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" [Test] procedure TestModifyInvoices() begin + Initialize(); + TestMultipleModifyInvoices(false, false); end; [Test] procedure TestEmptyModifyInvoices() begin + Initialize(); + TestMultipleModifyInvoices(true, false); end; [Test] procedure TestPartialModifyInvoices() begin + Initialize(); + TestMultipleModifyInvoices(false, true); end; @@ -436,6 +458,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" TargetURL: Text; InvoiceWithBlanksJSON: Text; begin + Initialize(); + // [SCENARIO 184721] Create Sales Invoice with all the Ids filled, use a PATCH method to blank the Ids and the Codes LibrarySales.CreateCustomerWithAddress(Customer); @@ -500,6 +524,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" NewInvoiceNumber: Text; NewInvoiceNumberJSON: Text; begin + Initialize(); + // [SCENARIO 184721] Create draft invoice and issue a patch request to change the number // [GIVEN] 1 draft invoice and a json with a new number LibrarySales.CreateSalesInvoice(SalesHeader); @@ -522,6 +548,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO 184721] Create unposted Sales invoice and use HTTP DELETE to delete it // [GIVEN] An unposted invoice CreateDraftSalesInvoice(SalesHeader); @@ -559,9 +587,12 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" TargetURL: Text; InvoiceJSON: Text; begin + Initialize(); + // [SCENARIO 184721] Create an invoice both through the client UI and through the API // [SCENARIO] and compare them. They should be the same and have the same fields autocompleted wherever needed. // [GIVEN] An unposted invoice + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryGraphDocumentTools.InitializeUIPage(); LibraryApplicationArea.DisableApplicationAreaSetup(); @@ -621,6 +652,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" TargetURL: Text; DiscountPct: Decimal; begin + Initialize(); + // [SCENARIO 184721] When an invoice is created,the GET Method should update the invoice and assign a total // [GIVEN] 2 invoices, one posted and one unposted without totals assigned LibraryApplicationArea.EnableFoundationSetup(); @@ -654,6 +687,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" DiscountAmt: Decimal; InvDiscAmount: Decimal; begin + Initialize(); + // [SCENARIO 184721] When an invoice is created, the GET Method should update the invoice and assign a total // [GIVEN] 2 invoices, one posted and one unposted with discount amount that should be redistributed LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending( @@ -689,6 +724,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" InvoiceJSON: Text; CurrencyCode: Code[10]; begin + Initialize(); + // [SCENARIO 184721] Create an invoice wihtout Customer throws an error // [GIVEN] a sales invoice JSON with currency only @@ -717,6 +754,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; InvoiceID: Text; begin + Initialize(); + // [SCENARIO 184721] Create Sales Invoice, use a PATCH method to change it and then verify the changes LibrarySales.CreateCustomerWithAddress(Customer); @@ -763,6 +802,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; InvoiceID: Text; begin + Initialize(); + // [SCENARIO 184721] Clearing manually set discount // [GIVEN] an item with unit price and unit cost @@ -819,6 +860,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" PostedInvoiceEmailAddress: Text; PostedInvoiceEmailSubject: Text; begin + Initialize(); + // [SCENARIO] User can post a sales invoice through the API. // [GIVEN] Draft sales invoice exists @@ -865,6 +908,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can post and send a sales invoice through the API. InitializeForSending(); @@ -903,6 +948,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can cancel a posted sales invoice through API. // [GIVEN] Posted sales invoice exists @@ -939,6 +986,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can cancel a posted sales invoice through API. InitializeForSending(); @@ -979,6 +1028,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can send a posted sales invoice through the API. InitializeForSending(); @@ -1011,6 +1062,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can send a draft sales invoice through the API. InitializeForSending(); @@ -1043,6 +1096,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can send a draft sales invoice through the API. InitializeForSending(); @@ -1083,6 +1138,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" CreditMemoEmailAddress: Text; CreditMemoEmailSubject: Text; begin + Initialize(); + // [SCENARIO] User can create a corrective credit memo for the posted sales invoice through the API. // [GIVEN] A posted sales invoice exists @@ -1127,6 +1184,8 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can map systemId with Draft Invoice SystemId // [GIVEN] Posted sales invoice exists @@ -1380,4 +1439,11 @@ codeunit 139809 "APIV2 - Sales Invoices E2E" LibraryGraphMgt.VerifyIDInJson(ResponseText); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesOrdArchE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesOrdArchE2E.Codeunit.al index 43a0cf41433..fff3228995e 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesOrdArchE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesOrdArchE2E.Codeunit.al @@ -25,6 +25,8 @@ codeunit 139927 "APIV2 - Sales Ord. Arch. E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Archive a sales order and use GET to retrieve the archive // [GIVEN] An archived sales order EnsureSalesOrderArchive(SalesHeaderArchive); @@ -45,6 +47,8 @@ codeunit 139927 "APIV2 - Sales Ord. Arch. E2E" TargetURL: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] GET a sales order archive with $expand=dimensionSetLines // [GIVEN] An archived sales order EnsureSalesOrderArchive(SalesHeaderArchive); @@ -67,6 +71,8 @@ codeunit 139927 "APIV2 - Sales Ord. Arch. E2E" TargetURL: Text; AttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a sales order archive with $expand=attachments // [GIVEN] An archived sales order EnsureSalesOrderArchive(SalesHeaderArchive); @@ -89,6 +95,8 @@ codeunit 139927 "APIV2 - Sales Ord. Arch. E2E" TargetURL: Text; DocumentAttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a sales order archive with $expand=documentAttachments // [GIVEN] An archived sales order EnsureSalesOrderArchive(SalesHeaderArchive); @@ -121,4 +129,10 @@ codeunit 139927 "APIV2 - Sales Ord. Arch. E2E" exit(TargetURL + '&$expand=' + ExpandValue); exit(TargetURL + '?$expand=' + ExpandValue); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesOrderLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesOrderLinesE2E.Codeunit.al index 280882e872d..568adfee40d 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesOrderLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesOrderLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139835 "APIV2 - Sales Order Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -30,9 +31,14 @@ codeunit 139835 "APIV2 - Sales Order Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibrarySales.SetStockoutWarning(false); LibraryApplicationArea.EnableFoundationSetup(); @@ -1477,9 +1483,6 @@ codeunit 139835 "APIV2 - Sales Order Lines E2E" - - - diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesOrdersE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesOrdersE2E.Codeunit.al index 16759bdf1b6..76098510107 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesOrdersE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesOrdersE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139811 "APIV2 - Sales Orders E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -38,6 +39,8 @@ codeunit 139811 "APIV2 - Sales Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO 184721] Create Sales Orders and use a GET method to retrieve them // [GIVEN] 2 orders in the table @@ -76,8 +79,12 @@ codeunit 139811 "APIV2 - Sales Orders E2E" TargetURL: Text; OrderJSON: Text; begin + Initialize(); + // [SCENARIO 184721] Create sales orders JSON and use HTTP POST to create them + LibraryGraphMgt.SetLicenseSafeWorkDate(); + // [GIVEN] a customer LibrarySales.CreateCustomerWithAddress(SellToCustomer); LibrarySales.CreateCustomerWithAddress(BillToCustomer); @@ -125,6 +132,8 @@ codeunit 139811 "APIV2 - Sales Orders E2E" TargetURL: Text; OrderJSON: Text; begin + Initialize(); + // [SCENARIO 184721] Create sales order for customer with location and use HTTP POST to create it // [GIVEN] an order with customer with location code @@ -168,6 +177,8 @@ codeunit 139811 "APIV2 - Sales Orders E2E" OrderJSON: Text; CurrencyCode: Code[10]; begin + Initialize(); + // [SCENARIO 184721] Create sales order with specific currency set and use HTTP POST to create it // [GIVEN] an order with a non-LCY currencyCode set @@ -203,18 +214,24 @@ codeunit 139811 "APIV2 - Sales Orders E2E" [Test] procedure TestModifyOrders() begin + Initialize(); + TestMultipleModifyOrders(false, false); end; [Test] procedure TestEmptyModifyOrders() begin + Initialize(); + TestMultipleModifyOrders(true, false); end; [Test] procedure TestPartialModifyOrders() begin + Initialize(); + TestMultipleModifyOrders(false, true); end; @@ -283,6 +300,8 @@ codeunit 139811 "APIV2 - Sales Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO 184721] Create sales orders and use HTTP DELETE to delete them // [GIVEN] 2 orders in the table @@ -329,7 +348,10 @@ codeunit 139811 "APIV2 - Sales Orders E2E" TargetURL: Text; OrderJSON: Text; begin + Initialize(); + // [SCENARIO 184721] Create an order both through the client UI and through the API and compare them. They should be the same and have the same fields autocompleted wherever needed. + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryGraphDocumentTools.InitializeUIPage(); // [GIVEN] a customer @@ -388,6 +410,8 @@ codeunit 139811 "APIV2 - Sales Orders E2E" TargetURL: Text; DiscountPct: Decimal; begin + Initialize(); + // [SCENARIO 184721] When an order is created, the GET Method should update the order and assign a total // [GIVEN] an order without totals assigned LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending(SalesHeader, DiscountPct, SalesHeader."Document Type"::Order); @@ -417,6 +441,8 @@ codeunit 139811 "APIV2 - Sales Orders E2E" DiscountAmt: Decimal; InvDiscAmount: Decimal; begin + Initialize(); + // [SCENARIO 184721] When an order is created, the GET Method should update the order and redistribute the discount amount // [GIVEN] an order with discount amount that should be redistributed LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending(SalesHeader, DiscountPct, SalesHeader."Document Type"::Order); @@ -451,6 +477,8 @@ codeunit 139811 "APIV2 - Sales Orders E2E" OrderNo: Text; OrderId: Guid; begin + Initialize(); + // [SCENARIO 184721] Create Sales Order, use a PATCH method to change it and then verify the changes // [GIVEN] an order with lines @@ -487,6 +515,8 @@ codeunit 139811 "APIV2 - Sales Orders E2E" ResponseText: Text; OrderNo: Text; begin + Initialize(); + // [SCENARIO 184721] Clearing manually set discount // [GIVEN] an order @@ -523,6 +553,8 @@ codeunit 139811 "APIV2 - Sales Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can ship and invoice a sales order through the API. // [GIVEN] a sales order with lines @@ -644,4 +676,11 @@ codeunit 139811 "APIV2 - Sales Orders E2E" LibraryGraphMgt.VerifyIDInJson(ResponseText); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesQuoteLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesQuoteLinesE2E.Codeunit.al index 803ae25520c..066bcc8c8e2 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesQuoteLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesQuoteLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139836 "APIV2 - Sales Quote Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -28,9 +29,14 @@ codeunit 139836 "APIV2 - Sales Quote Lines E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibrarySales.SetStockoutWarning(false); LibraryApplicationArea.EnableFoundationSetup(); @@ -998,6 +1004,5 @@ codeunit 139836 "APIV2 - Sales Quote Lines E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesQuotesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesQuotesE2E.Codeunit.al index e934a55669a..5d000a0d84f 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesQuotesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesQuotesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -60,6 +61,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create Sales Quotes and use a GET method to retrieve them // [GIVEN] 2 quotes in the table @@ -98,8 +101,12 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" QuoteJSON: Text; QuoteExists: Boolean; begin + Initialize(); + // [SCENARIO] Create sales quotes JSON and use HTTP POST to create them + LibraryGraphMgt.SetLicenseSafeWorkDate(); + // [GIVEN] a customer LibrarySales.CreateCustomerWithAddress(SellToCustomer); LibrarySales.CreateCustomerWithAddress(ShipToCustomer); @@ -143,6 +150,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" CurrencyCode: Code[10]; QuoteExists: Boolean; begin + Initialize(); + // [SCENARIO] Create sales quote with specific currency set and use HTTP POST to create it // [GIVEN] a quote with a non-LCY currencyCode set @@ -174,18 +183,24 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" [Test] procedure TestModifyQuotes() begin + Initialize(); + TestMultipleModifyQuotes(false, false); end; [Test] procedure TestEmptyModifyQuotes() begin + Initialize(); + TestMultipleModifyQuotes(true, false); end; [Test] procedure TestPartialModifyQuotes() begin + Initialize(); + TestMultipleModifyQuotes(false, true); end; @@ -269,6 +284,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create sales quotes and use HTTP DELETE to delete them // [GIVEN] 2 quotes in the table @@ -315,7 +332,10 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" QuoteJSON: Text; QuoteExists: Boolean; begin + Initialize(); + // [SCENARIO] Create a quote both through the client UI and through the API and compare them. They should be the same and have the same fields autocompleted wherever needed. + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryGraphDocumentTools.InitializeUIPage(); // [GIVEN] a customer @@ -369,6 +389,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" TargetURL: Text; DiscountPct: Decimal; begin + Initialize(); + // [SCENARIO] When a quote is created, the GET Method should update the quote and assign a total // [GIVEN] a quote without totals assigned LibraryGraphDocumentTools.CreateDocumentWithDiscountPctPending(SalesHeader, DiscountPct, SalesHeader."Document Type"::Quote); @@ -398,6 +420,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" DiscountAmt: Decimal; InvDiscAmount: Decimal; begin + Initialize(); + // [SCENARIO] When a quote is created, the GET Method should update the quote and redistribute the discount amount // [GIVEN] a quote with discount amount that should be redistributed @@ -435,6 +459,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" ResponseText: Text; QuoteID: Text; begin + Initialize(); + // [SCENARIO 184721] Create Sales Quote, use a PATCH method to change it and then verify the changes LibrarySales.CreateCustomerWithAddress(Customer); @@ -481,6 +507,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" ResponseText: Text; QuoteID: Text; begin + Initialize(); + // [SCENARIO 184721] Clearing manually set discount // [GIVEN] an item with unit price and unit cost @@ -529,6 +557,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] User can send a sales quote through the API. InitializeForSending(); @@ -572,6 +602,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" InvoiceEmailAddress: Text; InvoiceEmailSubject: Text; begin + Initialize(); + // [SCENARIO] User can convert a sales quote to a sales invoice through the API. // [GIVEN] Sales quote exists @@ -630,6 +662,8 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" OrderEmailAddress: Text; OrderEmailSubject: Text; begin + Initialize(); + // [SCENARIO] User can convert a sales quote to a sales order through the API. // [GIVEN] Sales quote exists @@ -847,4 +881,11 @@ codeunit 139823 "APIV2 - Sales Quotes E2E" end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesRetOrdersE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesRetOrdersE2E.Codeunit.al index c049e3837f6..fb3e557f46e 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesRetOrdersE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesRetOrdersE2E.Codeunit.al @@ -24,6 +24,8 @@ codeunit 139924 "APIV2 - Sales Ret. Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a sales return order and use GET to retrieve it // [GIVEN] A sales return order LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Return Order", ''); @@ -44,6 +46,8 @@ codeunit 139924 "APIV2 - Sales Ret. Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a sales return order and GET it by SystemId // [GIVEN] A sales return order LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::"Return Order", ''); @@ -66,6 +70,8 @@ codeunit 139924 "APIV2 - Sales Ret. Orders E2E" TargetURL: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] GET a sales return order with $expand=dimensionSetLines // [GIVEN] A sales return order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Return Order"); @@ -92,6 +98,8 @@ codeunit 139924 "APIV2 - Sales Ret. Orders E2E" TargetURL: Text; AttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a sales return order with $expand=attachments // [GIVEN] A sales return order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Return Order"); @@ -118,6 +126,8 @@ codeunit 139924 "APIV2 - Sales Ret. Orders E2E" TargetURL: Text; DocumentAttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a sales return order with $expand=documentAttachments // [GIVEN] A sales return order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Return Order"); @@ -144,6 +154,8 @@ codeunit 139924 "APIV2 - Sales Ret. Orders E2E" TargetURL: Text; PdfDocumentValue: Text; begin + Initialize(); + // [SCENARIO] GET a sales return order with $expand=pdfDocument // [GIVEN] A sales return order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Return Order"); @@ -170,6 +182,8 @@ codeunit 139924 "APIV2 - Sales Ret. Orders E2E" TargetURL: Text; LinesValue: Text; begin + Initialize(); + // [SCENARIO] GET a sales return order with $expand=salesReturnOrderLines // [GIVEN] A sales return order SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Return Order"); @@ -194,4 +208,10 @@ codeunit 139924 "APIV2 - Sales Ret. Orders E2E" exit(TargetURL + '&$expand=' + ExpandValue); exit(TargetURL + '?$expand=' + ExpandValue); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesShipLinesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesShipLinesE2E.Codeunit.al index 3081e6c6df6..343ee42123d 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesShipLinesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesShipLinesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139848 "APIV2 - Sales Ship. Lines E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -29,6 +30,8 @@ codeunit 139848 "APIV2 - Sales Ship. Lines E2E" LineNo: Integer; SequenceValue: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Line of a sales shipment // [GIVEN] A shipment with a line. @@ -63,6 +66,8 @@ codeunit 139848 "APIV2 - Sales Ship. Lines E2E" LineNo1: Text; LineNo2: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Lines of Sales Shipment // [GIVEN] An sales shipment with lines. @@ -105,6 +110,8 @@ codeunit 139848 "APIV2 - Sales Ship. Lines E2E" LineNo1: Text; LineNo2: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Lines of a sales shipment // [GIVEN] An sales shipment with lines. @@ -139,6 +146,8 @@ codeunit 139848 "APIV2 - Sales Ship. Lines E2E" LineIdTxt: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] Call GET on the Line of a sales shipment and expand the dimension set lines // [GIVEN] A shipment with a line. @@ -255,4 +264,11 @@ codeunit 139848 "APIV2 - Sales Ship. Lines E2E" exit(TargetURL); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalesShipmentsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalesShipmentsE2E.Codeunit.al index 230e2af2a5b..e451cc22429 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalesShipmentsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalesShipmentsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139847 "APIV2 - Sales Shipments E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -26,6 +27,8 @@ codeunit 139847 "APIV2 - Sales Shipments E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create 2 sales shipments (post sales order) and use a GET method to retrieve them // [GIVEN] 2 posted sales shipments @@ -57,6 +60,8 @@ codeunit 139847 "APIV2 - Sales Shipments E2E" ShipmentIdTxt: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] Call GET on a sales shipment and expand the dimension set lines // [GIVEN] A sales shipment. @@ -108,4 +113,11 @@ codeunit 139847 "APIV2 - Sales Shipments E2E" exit(TargetURL); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2SalespersonPurchE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2SalespersonPurchE2E.Codeunit.al index 00b9b57cfd8..cfcf542c9fd 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2SalespersonPurchE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2SalespersonPurchE2E.Codeunit.al @@ -14,9 +14,14 @@ codeunit 139882 "APIV2 - Salesperson/Purch E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2ShipmentMethodsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2ShipmentMethodsE2E.Codeunit.al index b7f25bf36dd..745c9b7b301 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2ShipmentMethodsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2ShipmentMethodsE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139805 "APIV2 - Shipment Methods E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -21,9 +22,14 @@ codeunit 139805 "APIV2 - Shipment Methods E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2TaxAreasE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2TaxAreasE2E.Codeunit.al index 3e579576ff6..f56aea0d5ec 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2TaxAreasE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2TaxAreasE2E.Codeunit.al @@ -24,9 +24,14 @@ codeunit 139826 "APIV2 - Tax Areas E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; @@ -288,4 +293,3 @@ codeunit 139826 "APIV2 - Tax Areas E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2TaxGroupsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2TaxGroupsE2E.Codeunit.al index 71058576f58..426f57009bb 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2TaxGroupsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2TaxGroupsE2E.Codeunit.al @@ -23,9 +23,14 @@ codeunit 139808 "APIV2 - Tax Groups E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; @@ -288,4 +293,3 @@ codeunit 139808 "APIV2 - Tax Groups E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2TransferOrdersE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2TransferOrdersE2E.Codeunit.al index 93bda0b6eed..feee4b30a17 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2TransferOrdersE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2TransferOrdersE2E.Codeunit.al @@ -27,6 +27,8 @@ codeunit 139926 "APIV2 - Transfer Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a transfer order and use GET to retrieve it // [GIVEN] A transfer order LibraryWarehouse.CreateTransferLocations(FromLocation, ToLocation, InTransitLocation); @@ -51,6 +53,8 @@ codeunit 139926 "APIV2 - Transfer Orders E2E" ResponseText: Text; TargetURL: Text; begin + Initialize(); + // [SCENARIO] Create a transfer order and GET it by SystemId // [GIVEN] A transfer order LibraryWarehouse.CreateTransferLocations(FromLocation, ToLocation, InTransitLocation); @@ -77,6 +81,8 @@ codeunit 139926 "APIV2 - Transfer Orders E2E" TargetURL: Text; DimensionSetValue: Text; begin + Initialize(); + // [SCENARIO] GET a transfer order with $expand=dimensionSetLines // [GIVEN] A transfer order if not TransferHeader.FindFirst() then begin @@ -106,6 +112,8 @@ codeunit 139926 "APIV2 - Transfer Orders E2E" TargetURL: Text; AttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a transfer order with $expand=attachments // [GIVEN] A transfer order if not TransferHeader.FindFirst() then begin @@ -135,6 +143,8 @@ codeunit 139926 "APIV2 - Transfer Orders E2E" TargetURL: Text; DocumentAttachmentsValue: Text; begin + Initialize(); + // [SCENARIO] GET a transfer order with $expand=documentAttachments // [GIVEN] A transfer order if not TransferHeader.FindFirst() then begin @@ -164,6 +174,8 @@ codeunit 139926 "APIV2 - Transfer Orders E2E" TargetURL: Text; PdfDocumentValue: Text; begin + Initialize(); + // [SCENARIO] GET a transfer order with $expand=pdfDocument // [GIVEN] A transfer order if not TransferHeader.FindFirst() then begin @@ -193,6 +205,8 @@ codeunit 139926 "APIV2 - Transfer Orders E2E" TargetURL: Text; LinesValue: Text; begin + Initialize(); + // [SCENARIO] GET a transfer order with $expand=transferOrderLines // [GIVEN] A transfer order if not TransferHeader.FindFirst() then begin @@ -217,4 +231,10 @@ codeunit 139926 "APIV2 - Transfer Orders E2E" exit(TargetURL + '&$expand=' + ExpandValue); exit(TargetURL + '?$expand=' + ExpandValue); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } diff --git a/src/Apps/W1/APIV2/test/src/APIV2TrialBalanceE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2TrialBalanceE2E.Codeunit.al index f94f316fc30..bd66781f754 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2TrialBalanceE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2TrialBalanceE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139818 "APIV2 - Trial Balance E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; trigger OnRun() @@ -60,9 +61,14 @@ codeunit 139818 "APIV2 - Trial Balance E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryApplicationArea.EnableFoundationSetup(); IsInitialized := true; end; @@ -85,4 +91,3 @@ codeunit 139818 "APIV2 - Trial Balance E2E" - diff --git a/src/Apps/W1/APIV2/test/src/APIV2UofME2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2UofME2E.Codeunit.al index 496d746235c..cad1e0faa0b 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2UofME2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2UofME2E.Codeunit.al @@ -24,6 +24,8 @@ codeunit 139812 "APIV2 - UofM E2E" UnitOfMeasure: Record "Unit of Measure"; Response: Text; begin + Initialize(); + // [SCENARIO] User can get the units of measure. // [GIVEN] Units of measure. @@ -44,6 +46,8 @@ codeunit 139812 "APIV2 - UofM E2E" Response: Text; OldDescription: Text; begin + Initialize(); + // [SCENARIO] User can update a unit of measure. // [GIVEN] Units of measure. @@ -73,6 +77,8 @@ codeunit 139812 "APIV2 - UofM E2E" UnitOfMeasure: Record "Unit of Measure"; Response: Text; begin + Initialize(); + // [SCENARIO] User can delete a unit of measure. // [GIVEN] Units of measure. @@ -94,6 +100,8 @@ codeunit 139812 "APIV2 - UofM E2E" Request: Text; "Code": Text; begin + Initialize(); + // [SCENARIO] User can insert a unit of measure. // [GIVEN] A new unit of measure. @@ -186,9 +194,14 @@ codeunit 139812 "APIV2 - UofM E2E" Format(UnitOfMeasure."International Standard Code"), InternationalStandardCode, StrSubstNo(WrongPropertyValueErr, 'internationalStandardCode')); end; -} - + local procedure Initialize() + begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; +} diff --git a/src/Apps/W1/APIV2/test/src/APIV2VendorPaymentsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2VendorPaymentsE2E.Codeunit.al index 0fc02556e63..b888df57ff4 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2VendorPaymentsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2VendorPaymentsE2E.Codeunit.al @@ -1,6 +1,7 @@ codeunit 139843 "APIV2 - Vendor Payments E2E" { Subtype = Test; + RequiredTestIsolation = Disabled; TestType = Uncategorized; TestPermissions = Disabled; @@ -884,10 +885,14 @@ codeunit 139843 "APIV2 - Vendor Payments E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryTestInitialize.OnTestInitialize(Codeunit::"APIV2 - Vendor Payments E2E"); - if not isInitialized then + if not isInitialized then begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); isInitialized := true; + end; LibraryTestInitialize.OnAfterTestSuiteInitialize(Codeunit::"APIV2 - Vendor Payments E2E"); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2VendorsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2VendorsE2E.Codeunit.al index fe84521cbd5..d073fd35a34 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2VendorsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2VendorsE2E.Codeunit.al @@ -25,9 +25,14 @@ codeunit 139803 "APIV2 - Vendors E2E" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/APIV2/test/src/APIV2WorkflowApproversE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2WorkflowApproversE2E.Codeunit.al index 4a11340aa53..05c9f4393ef 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2WorkflowApproversE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2WorkflowApproversE2E.Codeunit.al @@ -1,6 +1,5 @@ codeunit 139920 "APIV2 - Workflow Approvers E2E" { - Subtype = Test; TestType = IntegrationTest; TestPermissions = Disabled; @@ -29,6 +28,8 @@ codeunit 139920 "APIV2 - Workflow Approvers E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO] Check that workflow approvers can be retrieved via API // [GIVEN] A workflow exists LibraryWorkflow.CreateWorkflow(Workflow); @@ -64,4 +65,10 @@ codeunit 139920 "APIV2 - Workflow Approvers E2E" Assert.IsTrue(LibraryGraphMgt.GetObjectIDFromJSON(ResponseText, 'userId', UserId), 'Could not find workflow approver'); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } \ No newline at end of file diff --git a/src/Apps/W1/APIV2/test/src/APIV2WorkflowsE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2WorkflowsE2E.Codeunit.al index d5973d08348..802006851a8 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2WorkflowsE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2WorkflowsE2E.Codeunit.al @@ -1,6 +1,5 @@ codeunit 139921 "APIV2 - Workflows E2E" { - Subtype = Test; TestType = IntegrationTest; TestPermissions = Disabled; @@ -20,6 +19,8 @@ codeunit 139921 "APIV2 - Workflows E2E" TargetURL: Text; ResponseText: Text; begin + Initialize(); + // [SCENARIO] Check that workflows can be retrieved via API // [GIVEN] A workflow exists LibraryWorkflow.CreateWorkflow(Workflow); @@ -37,4 +38,10 @@ codeunit 139921 "APIV2 - Workflows E2E" Assert.IsTrue(LibraryGraphMgt.GetObjectIDFromJSON(ResponseText, 'id', WorkFlowId), 'Could not find workflow'); end; + + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; } \ No newline at end of file diff --git a/src/Apps/W1/APIV2/test/src/APIV2itemLedgEntriesE2E.Codeunit.al b/src/Apps/W1/APIV2/test/src/APIV2itemLedgEntriesE2E.Codeunit.al index f8f1374ccec..95c808218c0 100644 --- a/src/Apps/W1/APIV2/test/src/APIV2itemLedgEntriesE2E.Codeunit.al +++ b/src/Apps/W1/APIV2/test/src/APIV2itemLedgEntriesE2E.Codeunit.al @@ -3,6 +3,7 @@ codeunit 139854 "APIV2 - Item Ledg. Entries E2E" // version Test,ERM,W1,All Subtype = Test; + RequiredTestIsolation = Disabled; TestType = IntegrationTest; TestPermissions = Disabled; @@ -25,10 +26,15 @@ codeunit 139854 "APIV2 - Item Ledg. Entries E2E" LibraryERMCountryData: Codeunit "Library - ERM Country Data"; LibraryApplicationArea: Codeunit "Library - Application Area"; begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); + LibraryApplicationArea.EnableFoundationSetup(); if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateVATPostingSetup(); LibraryERMCountryData.UpdateGeneralLedgerSetup(); @@ -121,4 +127,3 @@ codeunit 139854 "APIV2 - Item Ledg. Entries E2E" - diff --git a/src/Apps/W1/EDocument/Test/src/Processing/EDocAPITest.Codeunit.al b/src/Apps/W1/EDocument/Test/src/Processing/EDocAPITest.Codeunit.al index 80b678db590..c9c5959b565 100644 --- a/src/Apps/W1/EDocument/Test/src/Processing/EDocAPITest.Codeunit.al +++ b/src/Apps/W1/EDocument/Test/src/Processing/EDocAPITest.Codeunit.al @@ -16,17 +16,20 @@ codeunit 135575 "E-Doc. API Test" TestType = IntegrationTest; TestPermissions = Disabled; + var + LibraryGraphMgt: Codeunit "Library - Graph Mgt"; + [Test] procedure GetEDocument() var PurchaseHeader: Record "Purchase Header"; EDocument: Record "E-Document"; - LibrarygraphMgt: Codeunit "Library - Graph Mgt"; TargetURL: Text; Response: Text; EDocsApiServiceNameTok: Label 'eDocuments', Locked = true; begin // [SCENARIO] Get E-Document from api page + Initialize(); // [GIVEN] Related document for e document CreatePurchaseHeader(PurchaseHeader); @@ -49,13 +52,13 @@ codeunit 135575 "E-Doc. API Test" EDocumentService: Record "E-Document Service"; Assert: Codeunit Assert; Any: Codeunit Any; - LibraryGraphMgt: Codeunit "Library - Graph Mgt"; JSONRequest: Text; TargetURL: Text; Response: Text; CreateEDocumentsServiceTxt: Label 'createEDocuments', Locked = true; begin // [SCENARIO] Create E-Document using api page + Initialize(); // [GIVEN] E-Document service EDocumentService.Init(); @@ -72,10 +75,15 @@ codeunit 135575 "E-Doc. API Test" Assert.AreEqual('', Response, 'Response should be empty.'); end; + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + local procedure VerifyEDocumentResponse(EDocument: Record "E-Document"; Response: Text) var Assert: Codeunit Assert; - LibraryGraphMgt: Codeunit "Library - Graph Mgt"; AmtInclVatTxt: Text; AmtExclVatTxt: Text; AmtInclVat: Decimal; @@ -152,8 +160,6 @@ codeunit 135575 "E-Doc. API Test" end; local procedure GetEDocumentCreateRequest(EDocumentServiceCode: Code[20]; var JSONRequest: Text) - var - LibraryGraphMgt: Codeunit "Library - Graph Mgt"; begin JSONRequest := LibraryGraphMgt.AddPropertytoJSON(JSONRequest, 'eDocumentService', EDocumentServiceCode); JSONRequest := LibraryGraphMgt.AddPropertytoJSON(JSONRequest, 'base64file', NavApp.GetResourceAsText('API/base64file.txt', TextEncoding::UTF8)); diff --git a/src/Apps/W1/ExpenseAgent/app/src/Travel Request/Codeunits/TravelRequestApproval.Codeunit.al b/src/Apps/W1/ExpenseAgent/app/src/Travel Request/Codeunits/TravelRequestApproval.Codeunit.al index b8ee5762dc7..8b290df2331 100644 --- a/src/Apps/W1/ExpenseAgent/app/src/Travel Request/Codeunits/TravelRequestApproval.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/app/src/Travel Request/Codeunits/TravelRequestApproval.Codeunit.al @@ -6,7 +6,6 @@ namespace Microsoft.ExpenseAgent; using Microsoft.Finance.SpendRequest; using System.Telemetry; -using System.Text; codeunit 7133 "Travel Request Approval" { @@ -318,13 +317,17 @@ codeunit 7133 "Travel Request Approval" var ExpenseApprovalSetup: Record "Expense Approval Setup"; ExpenseAgentSetup: Record "Expense Agent Setup"; - SelectionFilterManagement: Codeunit SelectionFilterManagement; - RecRef: RecordRef; + AssignedFilter: TextBuilder; begin ExpenseApprovalSetup.SetCurrentKey("Approver No."); ExpenseApprovalSetup.SetRange("Approver No.", ApproverExpenseUserNo); - RecRef.GetTable(ExpenseApprovalSetup); - RequestedForFilter := SelectionFilterManagement.GetSelectionFilter(RecRef, ExpenseApprovalSetup.FieldNo("Expense User No.")); + ExpenseApprovalSetup.SetLoadFields("Expense User No."); + // Ranges between setup rows could include expense users without any approval setup. + if ExpenseApprovalSetup.FindSet() then + repeat + AppendSubmitterFilter(AssignedFilter, ExpenseApprovalSetup."Expense User No."); + until ExpenseApprovalSetup.Next() = 0; + RequestedForFilter := AssignedFilter.ToText(); ExpenseAgentSetup.GetRecordOnce(); if ExpenseAgentSetup."Default Approver No." = ApproverExpenseUserNo then @@ -337,7 +340,6 @@ codeunit 7133 "Travel Request Approval" local procedure AppendDefaultSubmitters(var RequestedForFilter: Text) var ExpenseUser: Record "Expense User"; - SelectionFilterManagement: Codeunit SelectionFilterManagement; DefaultFilter: TextBuilder; begin if RequestedForFilter <> '' then @@ -348,14 +350,23 @@ codeunit 7133 "Travel Request Approval" ExpenseUser.SetLoadFields("No."); if ExpenseUser.FindSet() then repeat - if DefaultFilter.Length > 0 then - DefaultFilter.Append('|'); - DefaultFilter.Append(SelectionFilterManagement.AddQuotes(ExpenseUser."No.")); + AppendSubmitterFilter(DefaultFilter, ExpenseUser."No."); until ExpenseUser.Next() = 0; RequestedForFilter := DefaultFilter.ToText(); end; + local procedure AppendSubmitterFilter(var SubmitterFilter: TextBuilder; ExpenseUserNo: Code[20]) + var + ExpenseUserFilter: Record "Expense User"; + begin + // Serialize an exact value so filter operators in user numbers remain literal. + ExpenseUserFilter.SetRange("No.", ExpenseUserNo); + if SubmitterFilter.Length > 0 then + SubmitterFilter.Append('|'); + SubmitterFilter.Append(ExpenseUserFilter.GetFilter("No.")); + end; + var FeatureTelemetry: Codeunit "Feature Telemetry"; ExpenseActivityLogMgt: Codeunit "Expense Activity Log Mgt."; diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseActivityLogAPITest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseActivityLogAPITest.Codeunit.al index 90781c7634d..f0ec4e76f55 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseActivityLogAPITest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseActivityLogAPITest.Codeunit.al @@ -22,7 +22,6 @@ codeunit 148343 "Expense Activity Log API Test" LibraryGraphMgt: Codeunit "Library - Graph Mgt"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; LibrarySetupStorage: Codeunit "Library - Setup Storage"; - APITestAuthHelper: Codeunit "Expense API Test Auth Helper"; IsInitialized: Boolean; ServiceNameTok: Label 'expenseActivityLogEntries', Locked = true; ExpenseReportsServiceNameTok: Label 'expenseReports', Locked = true; @@ -476,11 +475,14 @@ codeunit 148343 "Expense Activity Log API Test" RequestBody.WriteTo(RequestText); ReportURL := LibraryGraphMgt.CreateTargetURLWithSubpage( Format(SubmitterExpenseUser.SystemId), Page::"Expense Users API", ExpenseUsersServiceNameTok, ExpenseReportsServiceNameTok); - ReportURL += '(' + LibraryGraphMgt.StripBrackets(Format(ExpenseReportHeader.SystemId)) + ')'; + ReportURL := LibraryGraphMgt.AppendPathToTargetURL( + ReportURL, '(' + LibraryGraphMgt.StripBrackets(Format(ExpenseReportHeader.SystemId)) + ')'); Commit(); // [WHEN] The standard submission action is requested through the submitting user. - LibraryGraphMgt.PostToWebServiceAndCheckResponseCode(ReportURL + '/' + SubmitWithCommentActionTok, RequestText, ResponseText, 200); + Clear(ResponseText); + LibraryGraphMgt.PostToWebServiceAndCheckResponseCode( + LibraryGraphMgt.AppendPathToTargetURL(ReportURL, '/' + SubmitWithCommentActionTok), RequestText, ResponseText, 200); // [THEN] Exactly one structured snapshot is visible without a new callback or capability. ExpenseActivityLogEntry.SetRange("Subject System ID", ExpenseReportHeader.SystemId); @@ -488,7 +490,8 @@ codeunit 148343 "Expense Activity Log API Test" Assert.RecordCount(ExpenseActivityLogEntry, 1); ExpenseActivityLogEntry.FindFirst(); Clear(ResponseText); - LibraryGraphMgt.GetFromWebServiceAndCheckResponseCode(ResponseText, ReportURL + '/' + ServiceNameTok, 200); + LibraryGraphMgt.GetFromWebServiceAndCheckResponseCode( + ResponseText, LibraryGraphMgt.AppendPathToTargetURL(ReportURL, '/' + ServiceNameTok), 200); VerifyPolicyCategoryCode(ResponseText, ExpenseCategory.Code); ResponseText := LowerCase(ResponseText); Assert.AreNotEqual(0, StrPos(ResponseText, '"eventtype":"policyevaluated"'), 'The event type must identify the policy snapshot.'); @@ -502,7 +505,8 @@ codeunit 148343 "Expense Activity Log API Test" HistoryURL := LibraryGraphMgt.CreateTargetURLWithSubpage( Format(SubmitterExpenseUser.SystemId), Page::"Expense Users API", ExpenseUsersServiceNameTok, ServiceNameTok); Clear(ResponseText); - LibraryGraphMgt.GetFromWebServiceAndCheckResponseCode(ResponseText, HistoryURL + '?$filter=historyActorRole eq ''Submitter''', 200); + LibraryGraphMgt.GetFromWebServiceAndCheckResponseCode( + ResponseText, LibraryGraphMgt.AppendQueryParameterToTargetURL(HistoryURL, '$filter=historyActorRole eq ''Submitter'''), 200); // [THEN] The real submitter sees the agent snapshot in the complete timeline. Assert.AreNotEqual(0, StrPos(LowerCase(ResponseText), LowerCase(LibraryGraphMgt.StripBrackets(Format(ExpenseActivityLogEntry.SystemId)))), 'The submitter timeline must contain the snapshot.'); @@ -511,7 +515,8 @@ codeunit 148343 "Expense Activity Log API Test" HistoryURL := LibraryGraphMgt.CreateTargetURLWithSubpage( Format(ApproverExpenseUser.SystemId), Page::"Expense Users API", ExpenseUsersServiceNameTok, ServiceNameTok); Clear(ResponseText); - LibraryGraphMgt.GetFromWebServiceAndCheckResponseCode(ResponseText, HistoryURL + '?$filter=historyActorRole eq ''Approver''', 200); + LibraryGraphMgt.GetFromWebServiceAndCheckResponseCode( + ResponseText, LibraryGraphMgt.AppendQueryParameterToTargetURL(HistoryURL, '$filter=historyActorRole eq ''Approver'''), 200); // [THEN] The agent event must not grant approver participation. Assert.AreEqual(0, StrPos(LowerCase(ResponseText), LowerCase(LibraryGraphMgt.StripBrackets(Format(ExpenseReportHeader.SystemId)))), 'The agent snapshot must not grant approver history access.'); @@ -803,7 +808,9 @@ codeunit 148343 "Expense Activity Log API Test" if IsInitialized then exit; - BindSubscription(APITestAuthHelper); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Expense Activity Log API Test"); LibraryERMCountryData.UpdateGeneralLedgerSetup(); if not ExpenseAgentSetup.Get() then begin diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseAgentSetupAPITest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseAgentSetupAPITest.Codeunit.al index 50bb3595b39..c5201316389 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseAgentSetupAPITest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseAgentSetupAPITest.Codeunit.al @@ -64,6 +64,9 @@ codeunit 148333 "Expense Agent Setup API Test" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Expense Agent Setup API Test"); LibraryExpense.SetupNumberSeriesInExpenseMgmt(); IsInitialized := true; diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseCapabilitiesAPITest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseCapabilitiesAPITest.Codeunit.al index 4436c873d54..6dceff107b7 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseCapabilitiesAPITest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseCapabilitiesAPITest.Codeunit.al @@ -18,7 +18,6 @@ codeunit 148318 "Expense Capabilities API Test" LibraryExpenseAgent: Codeunit "Library - Expense Agent"; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; - APITestAuthHelper: Codeunit "Expense API Test Auth Helper"; IsInitialized: Boolean; ServiceNameTok: Label 'expenseCapabilities', Locked = true; ActivityLogCapabilityNameTok: Label 'activityLog', Locked = true; @@ -104,8 +103,6 @@ codeunit 148318 "Expense Capabilities API Test" TargetURL: Text; ResponseText: Text; begin - // Excluded in BCApps CI until authenticated OData execution in a dedicated test company - // with disabled isolation is available; then remove this method's DisabledTest.json entry. // [SCENARIO] Travel requests are advertised when the supporting APIs are installed. Initialize(); @@ -248,7 +245,9 @@ codeunit 148318 "Expense Capabilities API Test" if IsInitialized then exit; - BindSubscription(APITestAuthHelper); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Expense Capabilities API Test"); IsInitialized := true; Commit(); diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/ExpensePerDiemLocationsTest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/ExpensePerDiemLocationsTest.Codeunit.al index 40fdf025b82..88d251c4260 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/ExpensePerDiemLocationsTest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/ExpensePerDiemLocationsTest.Codeunit.al @@ -17,7 +17,6 @@ codeunit 148349 "Expense PerDiem Locations Test" LibraryUtility: Codeunit "Library - Utility"; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; - APITestAuthHelper: Codeunit "Expense API Test Auth Helper"; IsInitialized: Boolean; [Test] @@ -82,11 +81,14 @@ codeunit 148349 "Expense PerDiem Locations Test" local procedure Initialize() begin + LibraryGraphMgt.SetLicenseSafeWorkDate(); LibraryTestInitialize.OnTestInitialize(Codeunit::"Expense PerDiem Locations Test"); if IsInitialized then exit; - BindSubscription(APITestAuthHelper); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Expense PerDiem Locations Test"); IsInitialized := true; Commit(); diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseProjectsAPITest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseProjectsAPITest.Codeunit.al index 45ed9ae6d25..63e7903018f 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseProjectsAPITest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseProjectsAPITest.Codeunit.al @@ -24,7 +24,6 @@ codeunit 148331 "Expense Projects API Test" LibraryHumanResource: Codeunit "Library - Human Resource"; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; - APITestAuthHelper: Codeunit "Expense API Test Auth Helper"; IsInitialized: Boolean; ExpenseUsersServiceNameTok: Label 'expenseUsers', Locked = true; ProjectsServiceNameTok: Label 'expenseProjects', Locked = true; @@ -723,7 +722,9 @@ codeunit 148331 "Expense Projects API Test" if IsInitialized then exit; - BindSubscription(APITestAuthHelper); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Expense Projects API Test"); if not ExpenseAgentSetup.Get() then begin ExpenseAgentSetup.Init(); diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseUsersAPITest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseUsersAPITest.Codeunit.al index f80c8eb6e80..1837a52d566 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseUsersAPITest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseUsersAPITest.Codeunit.al @@ -21,7 +21,6 @@ codeunit 148315 "Expense Users API Test" LibraryUtility: Codeunit "Library - Utility"; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; - APITestAuthHelper: Codeunit "Expense API Test Auth Helper"; IsInitialized: Boolean; ServiceNameTok: Label 'expenseUsers', Locked = true; EmployeesServiceNameTok: Label 'employees', Locked = true; @@ -125,7 +124,9 @@ codeunit 148315 "Expense Users API Test" if IsInitialized then exit; - BindSubscription(APITestAuthHelper); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Expense Users API Test"); if not ExpenseAgentSetup.Get() then begin ExpenseAgentSetup.Init(); diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseVATSpecAPITest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseVATSpecAPITest.Codeunit.al index 7c30f7723fa..a5bfe729b28 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseVATSpecAPITest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/ExpenseVATSpecAPITest.Codeunit.al @@ -11,6 +11,7 @@ codeunit 148348 "Expense VAT Spec. API Test" { Subtype = Test; TestType = IntegrationTest; + RequiredTestIsolation = Disabled; TestPermissions = Disabled; var @@ -19,7 +20,6 @@ codeunit 148348 "Expense VAT Spec. API Test" LibraryERM: Codeunit "Library - ERM"; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; - APITestAuthHelper: Codeunit "Expense API Test Auth Helper"; IsInitialized: Boolean; ServiceNameTok: Label 'expenseVATSpecifications', Locked = true; @@ -89,7 +89,9 @@ codeunit 148348 "Expense VAT Spec. API Test" if IsInitialized then exit; - BindSubscription(APITestAuthHelper); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Expense VAT Spec. API Test"); LibraryExpense.SetupNumberSeriesInExpenseMgmt(); LibraryERM.CreateVATBusinessPostingGroup(VATBusinessPostingGroup); diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/PoliciesToEvaluateAPITest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/PoliciesToEvaluateAPITest.Codeunit.al index ef512122f3d..a382c57ee52 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/PoliciesToEvaluateAPITest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/PoliciesToEvaluateAPITest.Codeunit.al @@ -18,7 +18,6 @@ codeunit 148345 "Policies To Evaluate API Test" LibraryExpense: Codeunit "Library - Expense"; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; - APITestAuthHelper: Codeunit "Expense API Test Auth Helper"; IsInitialized: Boolean; ExpenseReportLinesServiceNameTok: Label 'expenseReportLines', Locked = true; @@ -117,7 +116,9 @@ codeunit 148345 "Policies To Evaluate API Test" if IsInitialized then exit; - BindSubscription(APITestAuthHelper); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Policies To Evaluate API Test"); LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/PolicyEvaluationsAPITest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/PolicyEvaluationsAPITest.Codeunit.al index 97488f4294c..be07a540b99 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/PolicyEvaluationsAPITest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/PolicyEvaluationsAPITest.Codeunit.al @@ -18,7 +18,6 @@ codeunit 148344 "Policy Evaluations API Test" LibraryExpense: Codeunit "Library - Expense"; LibraryGraphMgt: Codeunit "Library - Graph Mgt"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; - APITestAuthHelper: Codeunit "Expense API Test Auth Helper"; IsInitialized: Boolean; ServiceNameTok: Label 'expensePolicyEvaluations', Locked = true; BadRequestResponseErr: Label 'Response code is 400', Locked = true; @@ -121,7 +120,9 @@ codeunit 148344 "Policy Evaluations API Test" if IsInitialized then exit; - BindSubscription(APITestAuthHelper); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Policy Evaluations API Test"); LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); diff --git a/src/Apps/W1/ExpenseAgent/test/src/API/TravelRequestsAPITest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/API/TravelRequestsAPITest.Codeunit.al index 2134bd14296..d54e4b2515b 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/API/TravelRequestsAPITest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/API/TravelRequestsAPITest.Codeunit.al @@ -10,12 +10,6 @@ using Microsoft.Finance.GeneralLedger.Setup; using Microsoft.Finance.SpendRequest; using Microsoft.HumanResources.Employee; -// These HTTP tests remain excluded in Expense_Agent_Tests.DisabledTest.json until the -// authentication prerequisite provides an authenticated OData endpoint and a dedicated -// test company with committed fixtures and disabled test isolation. -// In-process employee filtering, traveler mapping/navigation, lifecycle, date, and scope coverage -// in "Spend Request Test", and restrictive role coverage in "Expense Permissions Test", remain enabled. -// Only the HTTP scenarios are excluded. codeunit 148347 "Travel Requests API Test" { Subtype = Test; @@ -31,7 +25,6 @@ codeunit 148347 "Travel Requests API Test" LibraryHumanResource: Codeunit "Library - Human Resource"; LibraryRandom: Codeunit "Library - Random"; LibraryTestInitialize: Codeunit "Library - Test Initialize"; - APITestAuthHelper: Codeunit "Expense API Test Auth Helper"; IsInitialized: Boolean; ExpenseUsersServiceNameTok: Label 'expenseUsers', Locked = true; #if not CLEAN30 @@ -1291,7 +1284,9 @@ codeunit 148347 "Travel Requests API Test" if IsInitialized then exit; - BindSubscription(APITestAuthHelper); + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"Travel Requests API Test"); if not ExpenseAgentSetup.Get() then begin ExpenseAgentSetup.Init(); diff --git a/src/Apps/W1/ExpenseAgent/test/src/ExpensePermissionsTest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/ExpensePermissionsTest.Codeunit.al index aa05633221e..89ecec0c706 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/ExpensePermissionsTest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/ExpensePermissionsTest.Codeunit.al @@ -32,6 +32,9 @@ codeunit 148338 "Expense Permissions Test" AutomationPermissionSetTok: Label 'Exp. Auto Test', Locked = true; D365BasicPermissionSetTok: Label 'D365 BASIC', Locked = true; ExpenseAgentPermissionSetTok: Label 'Expense Agent', Locked = true; + DetailOnlyPermissionSetTok: Label 'Exp. Detail Test', Locked = true; + HeaderModifyPermissionErr: Label 'TableData %1 %2 IndirectModify', Comment = '%1 = Spend Request table ID, %2 = Spend Request table caption', Locked = true; + RequestMustBeOpenErr: Label 'The %1 %2 must have the status %3.', Comment = '%1 = document type description, %2 = document number, %3 = Open status'; ExpenseAgentAppIdTok: Label '66efe10c-8033-403b-a86d-77c0887178ba', Locked = true; ExpenseMgmtAdminPermissionSetTok: Label 'Expense Mgmt. Admin', Locked = true; SecurityPermissionSetTok: Label 'SECURITY', Locked = true; @@ -63,15 +66,100 @@ codeunit 148338 "Expense Permissions Test" [Test] procedure D365BasicCanUpdateTravelRequestDetailsIndirectly() begin + // [SCENARIO 646383] D365 BASIC applies successive detail amount deltas without direct header or detail writes. + Initialize(); VerifyTravelRequestDetailUpdateIndirectly(D365BasicPermissionSetTok); end; [Test] procedure ExpenseAgentCanUpdateTravelRequestDetailsIndirectly() begin + // [SCENARIO 646383] Expense Agent applies successive detail amount deltas without direct header or detail writes. + Initialize(); VerifyTravelRequestDetailUpdateIndirectly(ExpenseAgentPermissionSetTok); end; + [Test] + procedure DetailAmountUpdateFailsWithoutHeaderModifyPermission() + var + SpendRequest: Record "Spend Request"; + SpendRequestDetail: Record "Spend Request Detail"; + TravelRequestSubform: TestPage "Travel Request Subform"; + SpendRequestCanWrite: Boolean; + SpendRequestDetailCanWrite: Boolean; + PermissionErrorCode: Text; + PermissionErrorText: Text; + begin + // [SCENARIO 646383] A caller with only header read and indirect detail modify cannot update the header through an amount change. + Initialize(); + + // [GIVEN] An open request "R" with a committed detail "D" worth 10. + LibraryExpense.CreateSpendRequest(SpendRequest); + LibraryExpense.CreateSpendRequestDetail(SpendRequestDetail, SpendRequest."No.", 10); + VerifyTravelRequestAmounts(SpendRequest, SpendRequestDetail, 10); + Commit(); + LibraryLowerPermissions.StartLoggingNAVPermissions(); + LibraryLowerPermissions.SetExactPermissionSet(DetailOnlyPermissionSetTok); + SpendRequestCanWrite := SpendRequest.WritePermission(); + SpendRequestDetailCanWrite := SpendRequestDetail.WritePermission(); + TravelRequestSubform.OpenEdit(); + TravelRequestSubform.GoToRecord(SpendRequestDetail); + + // [WHEN] The caller changes the amount through the public page. + asserterror TravelRequestSubform.Amount.SetValue(20); + PermissionErrorCode := GetLastErrorCode(); + PermissionErrorText := GetLastErrorText(); + TravelRequestSubform.Close(); + RestoreFullPermissions(); + LibraryLowerPermissions.StopLoggingNAVPermissions(); + + // [THEN] The page reports the specific header modify denial and neither record changes. + VerifyCapturedPageError(PermissionErrorCode, PermissionErrorText, + StrSubstNo(HeaderModifyPermissionErr, Database::"Spend Request", SpendRequest.TableCaption())); + Assert.IsFalse(SpendRequestCanWrite, 'The caller must not have direct request write permission.'); + Assert.IsFalse(SpendRequestDetailCanWrite, 'The caller must not have direct detail write permission.'); + VerifyTravelRequestAmounts(SpendRequest, SpendRequestDetail, 10); + end; + + [Test] + procedure ReleasedTravelRequestDetailAmountCannotBeUpdatedIndirectly() + var + SpendRequest: Record "Spend Request"; + SpendRequestDetail: Record "Spend Request Detail"; + TravelRequestSubform: TestPage "Travel Request Subform"; + ValidationErrorCode: Text; + ValidationErrorText: Text; + begin + // [SCENARIO 646383] Indirect header modification does not bypass the Open status guard. + Initialize(); + + // [GIVEN] A released request "R" with a committed detail "D" worth 10. + LibraryExpense.CreateSpendRequest(SpendRequest); + LibraryExpense.CreateSpendRequestDetail(SpendRequestDetail, SpendRequest."No.", 10); + VerifyTravelRequestAmounts(SpendRequest, SpendRequestDetail, 10); + LibraryExpense.SetSpendRequestStatus(SpendRequest, SpendRequest.Status::Released); + Commit(); + LibraryLowerPermissions.StartLoggingNAVPermissions(); + LibraryLowerPermissions.SetExactPermissionSet(ExpenseAgentPermissionSetTok); + TravelRequestSubform.OpenEdit(); + TravelRequestSubform.GoToRecord(SpendRequestDetail); + + // [WHEN] The caller changes the amount through the public page. + asserterror TravelRequestSubform.Amount.SetValue(20); + ValidationErrorCode := GetLastErrorCode(); + ValidationErrorText := GetLastErrorText(); + TravelRequestSubform.Close(); + RestoreFullPermissions(); + LibraryLowerPermissions.StopLoggingNAVPermissions(); + + // [THEN] The status guard rejects the change and the released request retains both amounts. + VerifyCapturedPageError(ValidationErrorCode, ValidationErrorText, + StrSubstNo(RequestMustBeOpenErr, SpendRequest.GetDocumentTypeDescription(), SpendRequest."No.", SpendRequest.Status::Open)); + VerifyTravelRequestAmounts(SpendRequest, SpendRequestDetail, 10); + SpendRequest.Get(SpendRequest."No."); + Assert.AreEqual(SpendRequest.Status::Released, SpendRequest.Status, 'The denied amount change must preserve the Released status.'); + end; + [Test] procedure D365BasicCanInsertActivityIndirectly() begin @@ -139,20 +227,29 @@ codeunit 148338 "Expense Permissions Test" ExpenseUser: Record "Expense User"; Approver: Record "Expense User"; TravelRequestApproval: Codeunit "Travel Request Approval"; + ExpenseUserCanRead: Boolean; + PermissionErrorCode: Text; + PermissionErrorText: Text; begin // [SCENARIO] An employee-only caller cannot approve requests without access to Expense User data. Initialize(); CreateTravelRequestApprovalScenario(SpendRequest, ExpenseUser, Approver); + // Preserve the fixture for the post-denial checks when asserterror rolls back. Commit(); LibraryLowerPermissions.StartLoggingNAVPermissions(); - SetCallerPermissions(EmployeeOnlyPermissionSetTok, ExpenseUser); + LibraryLowerPermissions.SetExactPermissionSet(EmployeeOnlyPermissionSetTok); + ExpenseUserCanRead := ExpenseUser.ReadPermission(); asserterror TravelRequestApproval.Approve(SpendRequest, Approver."No."); - Assert.ExpectedErrorCode('DB:ClientReadDenied'); - Assert.ExpectedError(ExpenseUser.TableCaption()); + // Capture the denial before permission cleanup can change the last-error state. + PermissionErrorCode := GetLastErrorCode(); + PermissionErrorText := GetLastErrorText(); RestoreFullPermissions(); LibraryLowerPermissions.StopLoggingNAVPermissions(); + Assert.AreEqual('DB:ClientReadDenied', PermissionErrorCode, 'Approval must fail because Expense User read access is denied.'); + Assert.ExpectedMessage(ExpenseUser.TableCaption(), PermissionErrorText); + Assert.IsFalse(ExpenseUserCanRead, 'The caller must not have direct access to Expense User.'); SpendRequest.Get(SpendRequest."No."); Assert.AreEqual(SpendRequest.Status::Released, SpendRequest.Status, 'A denied approval must preserve the request status.'); ExpenseReportHeader.SetRange("Spend Request No.", SpendRequest."No."); @@ -563,8 +660,7 @@ codeunit 148338 "Expense Permissions Test" SpendRequestDetail: Record "Spend Request Detail"; TravelRequestSubform: TestPage "Travel Request Subform"; begin - // [SCENARIO] Editing a detail through its page can update both the line and its header total. - Initialize(); + // [GIVEN] An open request "R" with a detail "D" worth 10. LibraryExpense.CreateSpendRequest(SpendRequest); LibraryExpense.CreateSpendRequestDetail(SpendRequestDetail, SpendRequest."No.", 10); @@ -583,10 +679,41 @@ codeunit 148338 "Expense Permissions Test" LibraryLowerPermissions.StopLoggingNAVPermissions(); // [THEN] Both the line change and the base table's header update are persisted. + VerifyTravelRequestAmounts(SpendRequest, SpendRequestDetail, 20); + + // [GIVEN] The same exact role still has no direct writes after the first update. + LibraryLowerPermissions.StartLoggingNAVPermissions(); + LibraryLowerPermissions.SetExactPermissionSet(PermissionSetId); + Assert.IsFalse(SpendRequest.WritePermission(), 'The caller must not have direct request write permission.'); + Assert.IsFalse(SpendRequestDetail.WritePermission(), 'The caller must not have direct detail write permission.'); + + // [WHEN] The persisted detail amount is increased again from 20 to 30. + Clear(TravelRequestSubform); + TravelRequestSubform.OpenEdit(); + TravelRequestSubform.GoToRecord(SpendRequestDetail); + TravelRequestSubform.Amount.SetValue(30); + TravelRequestSubform.Close(); + RestoreFullPermissions(); + LibraryLowerPermissions.StopLoggingNAVPermissions(); + + // [THEN] The second update applies only its delta, not the entire new amount. + VerifyTravelRequestAmounts(SpendRequest, SpendRequestDetail, 30); + end; + + local procedure VerifyTravelRequestAmounts(var SpendRequest: Record "Spend Request"; var SpendRequestDetail: Record "Spend Request Detail"; ExpectedAmount: Decimal) + begin SpendRequestDetail.Get(SpendRequestDetail."Spend Request No.", SpendRequestDetail."Line No."); SpendRequest.Get(SpendRequest."No."); - Assert.AreEqual(20, SpendRequestDetail."Expected Amount", 'The detail amount must be updated through indirect permissions.'); - Assert.AreEqual(20, SpendRequest."Total Expected Amount (LCY)", 'The detail update must also update the header total.'); + Assert.AreEqual(ExpectedAmount, SpendRequestDetail."Expected Amount", 'The detail amount must match the page operation.'); + Assert.AreEqual(ExpectedAmount, SpendRequestDetail."Expected Amount (LCY)", 'The LCY detail amount must match the page operation.'); + Assert.AreEqual(ExpectedAmount, SpendRequest."Total Expected Amount", 'The request amount must reflect the detail delta exactly once.'); + Assert.AreEqual(ExpectedAmount, SpendRequest."Total Expected Amount (LCY)", 'The LCY request amount must reflect the detail delta exactly once.'); + end; + + local procedure VerifyCapturedPageError(ErrorCode: Text; ErrorText: Text; ExpectedErrorText: Text) + begin + Assert.AreEqual('TestValidation', ErrorCode, 'The amount field must fail through the TestPage validation wrapper.'); + Assert.ExpectedMessage(ExpectedErrorText, ErrorText); end; local procedure VerifyCompanyEmailSynchronization(PermissionSetId: Code[20]) diff --git a/src/Apps/W1/ExpenseAgent/test/src/Helper/ExpenseAPITestAuthHelper.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/Helper/ExpenseAPITestAuthHelper.Codeunit.al deleted file mode 100644 index 4e34344be7a..00000000000 --- a/src/Apps/W1/ExpenseAgent/test/src/Helper/ExpenseAPITestAuthHelper.Codeunit.al +++ /dev/null @@ -1,61 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// ------------------------------------------------------------------------------------------------ -namespace Microsoft.Test.ExpenseAgent; - -using System.Azure.KeyVault; -using System.Environment; -using System.Integration; -using System.Security.AccessControl; - -/// -/// Test-only authentication helper for the API test codeunits in this app. -/// -codeunit 148332 "Expense API Test Auth Helper" -{ - Access = Internal; - EventSubscriberInstance = Manual; - - var - NavServerUserPasswordKeyTok: Label 'NavServerUserPassword', Locked = true; - - [EventSubscriber(ObjectType::Codeunit, Codeunit::"Library - Graph Mgt", OnAfterInitializeWebRequestWithURL, '', false, false)] - local procedure OnAfterInitializeWebRequest(var HttpWebRequestMgt: Codeunit "Http Web Request Mgt.") - var - Password: SecretText; - begin - if not ShouldInjectBasicAuth() then - exit; - if not TryGetPassword(Password) then - exit; - HttpWebRequestMgt.AddBasicAuthentication(UserId(), Password); - end; - - local procedure ShouldInjectBasicAuth(): Boolean - var - User: Record User; - EnvironmentInfo: Codeunit "Environment Information"; - begin - if EnvironmentInfo.IsSaaSInfrastructure() then - exit(false); - - // If the current user authenticates via Windows - if not User.Get(UserSecurityId()) then - exit(false); - if User."Windows Security ID" <> '' then - exit(false); - - // Inject Basic auth when using username password authentication. - exit(true); - end; - - [TryFunction] - local procedure TryGetPassword(var Password: SecretText) - var - AzureKeyVault: Codeunit "Azure Key Vault"; - begin - AzureKeyVault.GetAzureKeyVaultSecret(NavServerUserPasswordKeyTok, Password); - end; -} - diff --git a/src/Apps/W1/ExpenseAgent/test/src/Permissions/ExpDetailTest.PermissionSet.al b/src/Apps/W1/ExpenseAgent/test/src/Permissions/ExpDetailTest.PermissionSet.al new file mode 100644 index 00000000000..9b2f1c33517 --- /dev/null +++ b/src/Apps/W1/ExpenseAgent/test/src/Permissions/ExpDetailTest.PermissionSet.al @@ -0,0 +1,20 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Test.ExpenseAgent; + +using Microsoft.Finance.SpendRequest; +using System.Security.AccessControl; + +permissionset 148303 "Exp. Detail Test" +{ + Access = Internal; + Assignable = false; + IncludedPermissionSets = "D365 READ"; + + // Keep the header read-only, while allowing the page to modify a detail indirectly. + Permissions = tabledata "Spend Request Detail" = m, + codeunit Assert = X, + codeunit "Library - Lower Permissions" = X; +} diff --git a/src/Apps/W1/ExpenseAgent/test/src/SpendRequestTest.Codeunit.al b/src/Apps/W1/ExpenseAgent/test/src/SpendRequestTest.Codeunit.al index b18c4701d05..c93fa9338d1 100644 --- a/src/Apps/W1/ExpenseAgent/test/src/SpendRequestTest.Codeunit.al +++ b/src/Apps/W1/ExpenseAgent/test/src/SpendRequestTest.Codeunit.al @@ -62,6 +62,8 @@ codeunit 148339 "Spend Request Test" UnassignedTravelRequestHiddenMsg: Label 'The approver should not see a travel request assigned to another approver.'; DefaultTravelRequestVisibleMsg: Label 'The default approver should see travel requests without an assigned approver.'; ApproverWithoutRequestsMsg: Label 'An approver without assigned travel requests should receive an empty result.'; + ApproverFilterExpectedRequestErr: Label '%1 Requested For filter: %2. Expected request: %3.', Comment = '%1 = assertion message, %2 = Requested For filter, %3 = expected request number'; + ApproverFilterUnexpectedRequestErr: Label '%1 Requested For filter: %2. Expected request: %3. Unauthorized request: %4.', Comment = '%1 = assertion message, %2 = Requested For filter, %3 = expected request number, %4 = unauthorized request number'; SpendReqNoSetMsg: Label 'The Spend Request No. should be assigned to the expense report line.'; HeaderSpendReqNoSetMsg: Label 'The Spend Request No. should be assigned to the expense report header.'; HeaderCloseFlagMsg: Label 'The header should store the confirmed close flag.'; @@ -1877,21 +1879,108 @@ codeunit 148339 "Spend Request Test" procedure ApproverFilterReturnsDefaultApproverTravelRequests() begin // [SCENARIO] The default approver sees requests without an explicit approval assignment. - VerifyDefaultApproverFilter('', ''); + Initialize(); + + VerifyDefaultApproverFilter('', '', true); end; [Test] procedure DefaultApproverFilterQuotesWildcardUserNo() begin // [SCENARIO] A literal wildcard user number must not expose another approver's requests. - VerifyDefaultApproverFilter('*', 'TR-OTHER'); + Initialize(); + + VerifyDefaultApproverFilter('*', 'TR-OTHER', true); end; [Test] procedure DefaultApproverFilterQuotesPipeUserNo() begin // [SCENARIO] A pipe in a user number must not become an OR filter for other users. - VerifyDefaultApproverFilter('TR-A|TR-B', 'TR-A'); + Initialize(); + + VerifyDefaultApproverFilter('TR-A|TR-B', 'TR-A', true); + end; + + [Test] + procedure ApproverFilterQuotesExplicitWildcardUserNo() + begin + // [SCENARIO] An explicitly assigned literal wildcard user must not expose another approver's requests. + Initialize(); + + VerifyDefaultApproverFilter('*', 'TR-OTHER', false); + end; + + [Test] + procedure ApproverFilterQuotesExplicitPipeUserNo() + begin + // [SCENARIO] An explicitly assigned user with a pipe in its number must not expose another approver's requests. + Initialize(); + + VerifyDefaultApproverFilter('TR-A|TR-B', 'TR-A', false); + end; + + [Test] + procedure ApproverFilterDoesNotIncludeUnassignedUserBetweenAssignedUsers() + var + FirstTravelRequest: Record "Spend Request"; + LastTravelRequest: Record "Spend Request"; + UnassignedTravelRequest: Record "Spend Request"; + FilteredTravelRequest: Record "Spend Request"; + FirstExpenseUser: Record "Expense User"; + LastExpenseUser: Record "Expense User"; + UnassignedExpenseUser: Record "Expense User"; + AssignedApprover: Record "Expense User"; + DefaultApprover: Record "Expense User"; + ExpenseApprovalSetup: Record "Expense Approval Setup"; + TravelRequestApproval: Codeunit "Travel Request Approval"; + begin + // [SCENARIO] Adjacent approval setups must not expose a user between them who belongs to another default approver. + Initialize(); + + // [GIVEN] Approver "A" and default approver "B", with their user numbers outside the tested range. + ExpenseApprovalSetup.DeleteAll(); + LibraryExpense.UpdateEnableAgentInAgentSetup(true); + CreateApprover(AssignedApprover); + AssignedApprover.Rename('FILTER-APP-A'); + CreateApprover(DefaultApprover); + DefaultApprover.Rename('FILTER-APP-B'); + SetDefaultApprover(DefaultApprover."No."); + + // [GIVEN] Released requests for "TR-A" and "TR-C" explicitly assigned to "A". + CreateReleasableSpendRequest(FirstTravelRequest, FirstExpenseUser); + FirstExpenseUser.Rename('TR-A'); + FirstTravelRequest.Get(FirstTravelRequest."No."); + LibraryExpense.SetSpendRequestStatus(FirstTravelRequest, FirstTravelRequest.Status::Released); + ExpenseApprovalSetup.Get(FirstExpenseUser."No."); + ExpenseApprovalSetup.Validate("Approver No.", AssignedApprover."No."); + ExpenseApprovalSetup.Modify(true); + CreateReleasableSpendRequest(LastTravelRequest, LastExpenseUser); + LastExpenseUser.Rename('TR-C'); + LastTravelRequest.Get(LastTravelRequest."No."); + LibraryExpense.SetSpendRequestStatus(LastTravelRequest, LastTravelRequest.Status::Released); + ExpenseApprovalSetup.Get(LastExpenseUser."No."); + ExpenseApprovalSetup.Validate("Approver No.", AssignedApprover."No."); + ExpenseApprovalSetup.Modify(true); + + // [GIVEN] A released request for "TR-B" with no setup, so it belongs to default approver "B". + CreateReleasableSpendRequest(UnassignedTravelRequest, UnassignedExpenseUser); + UnassignedExpenseUser.Rename('TR-B'); + UnassignedTravelRequest.Get(UnassignedTravelRequest."No."); + LibraryExpense.SetSpendRequestStatus(UnassignedTravelRequest, UnassignedTravelRequest.Status::Released); + ExpenseApprovalSetup.Get(UnassignedExpenseUser."No."); + ExpenseApprovalSetup.Delete(true); + VerifyApproverFilterRangeGapSetup( + FirstTravelRequest, LastTravelRequest, UnassignedTravelRequest, AssignedApprover."No.", DefaultApprover."No."); + + // [WHEN] "A"'s filter is applied to pending travel requests. + FilteredTravelRequest.SetRange("Document Type", FilteredTravelRequest."Document Type"::"Travel Request"); + FilteredTravelRequest.SetRange(Status, FilteredTravelRequest.Status::Released); + TravelRequestApproval.ApplyApproverFilter(FilteredTravelRequest, AssignedApprover.SystemId); + + // [THEN] The requests for "TR-A" and "TR-C" are visible, but the request for "TR-B" is hidden. + VerifyApproverFilterRangeGapResults( + FilteredTravelRequest, FirstTravelRequest."No.", LastTravelRequest."No.", UnassignedTravelRequest."No."); end; [Test] @@ -3173,7 +3262,7 @@ codeunit 148339 "Spend Request Test" ExpenseAgentSetup.Modify(true); end; - local procedure VerifyDefaultApproverFilter(DefaultExpenseUserNo: Code[20]; OtherExpenseUserNo: Code[20]) + local procedure VerifyDefaultApproverFilter(DefaultExpenseUserNo: Code[20]; OtherExpenseUserNo: Code[20]; UseDefaultFallback: Boolean) var DefaultTravelRequest: Record "Spend Request"; OtherTravelRequest: Record "Spend Request"; @@ -3182,11 +3271,13 @@ codeunit 148339 "Spend Request Test" OtherExpenseUser: Record "Expense User"; DefaultApprover: Record "Expense User"; OtherApprover: Record "Expense User"; + ExpenseApprovalSetup: Record "Expense Approval Setup"; TravelRequestApproval: Codeunit "Travel Request Approval"; + ExpectedApproverNo: Code[20]; begin - Initialize(); - - // [GIVEN] A default approver, an unassigned request, and a request assigned to another approver. + // [GIVEN] Default approver "A", a request for "U", and another request assigned to approver "B". + // Initialize deletes expense users without their OnDelete trigger, leaving approval setups behind. + ExpenseApprovalSetup.DeleteAll(); LibraryExpense.UpdateEnableAgentInAgentSetup(true); CreateApprover(DefaultApprover); SetDefaultApprover(DefaultApprover."No."); @@ -3194,28 +3285,93 @@ codeunit 148339 "Spend Request Test" if DefaultExpenseUserNo <> '' then begin DefaultExpenseUser.Rename(DefaultExpenseUserNo); DefaultTravelRequest.Get(DefaultTravelRequest."No."); - DefaultTravelRequest.TestField("Requested For", DefaultExpenseUserNo); + Assert.AreEqual(DefaultExpenseUserNo, DefaultTravelRequest."Requested For", 'The request must retain the literal renamed user number.'); end; LibraryExpense.SetSpendRequestStatus(DefaultTravelRequest, DefaultTravelRequest.Status::Released); CreateReleasableSpendRequest(OtherTravelRequest, OtherExpenseUser); if OtherExpenseUserNo <> '' then begin OtherExpenseUser.Rename(OtherExpenseUserNo); OtherTravelRequest.Get(OtherTravelRequest."No."); - OtherTravelRequest.TestField("Requested For", OtherExpenseUserNo); + Assert.AreEqual(OtherExpenseUserNo, OtherTravelRequest."Requested For", 'The other request must retain the literal renamed user number.'); end; CreateApproverForExpenseUser(OtherApprover, OtherExpenseUser); LibraryExpense.SetSpendRequestStatus(OtherTravelRequest, OtherTravelRequest.Status::Released); + // [GIVEN] "U" is either explicitly assigned to "A" or has no setup and must use the default fallback. + // Both setting the default approver and inserting expense users create explicit assignments. + ExpenseApprovalSetup.Get(DefaultExpenseUser."No."); + Assert.AreEqual(DefaultApprover."No.", ExpenseApprovalSetup."Approver No.", 'The initial fixture must exercise the explicit-assignment path.'); + ExpectedApproverNo := DefaultApprover."No."; + if UseDefaultFallback then begin + ExpenseApprovalSetup.Delete(true); + ExpectedApproverNo := ''; + end; + DefaultExpenseUser.CalcFields("Approver No."); + Assert.AreEqual(ExpectedApproverNo, DefaultExpenseUser."Approver No.", 'The fixture must select the intended explicit-assignment or default-fallback path.'); + ExpenseApprovalSetup.Get(OtherExpenseUser."No."); + Assert.AreEqual(OtherApprover."No.", ExpenseApprovalSetup."Approver No.", 'The other request must remain explicitly assigned to another approver.'); + // [WHEN] The default approver's filter is applied to pending travel requests. FilteredTravelRequest.SetRange("Document Type", FilteredTravelRequest."Document Type"::"Travel Request"); FilteredTravelRequest.SetRange(Status, FilteredTravelRequest.Status::Released); TravelRequestApproval.ApplyApproverFilter(FilteredTravelRequest, DefaultApprover.SystemId); - // [THEN] Only the literal unassigned user's request is visible, not the other approver's request. + // [THEN] Only "U"'s literal request is visible, not the request assigned to "B". FilteredTravelRequest.SetRange("No.", DefaultTravelRequest."No."); - Assert.IsFalse(FilteredTravelRequest.IsEmpty(), DefaultTravelRequestVisibleMsg); + Assert.IsFalse( + FilteredTravelRequest.IsEmpty(), + StrSubstNo(ApproverFilterExpectedRequestErr, + DefaultTravelRequestVisibleMsg, FilteredTravelRequest.GetFilter("Requested For"), DefaultTravelRequest."No.")); FilteredTravelRequest.SetRange("No.", OtherTravelRequest."No."); - Assert.IsTrue(FilteredTravelRequest.IsEmpty(), UnassignedTravelRequestHiddenMsg); + Assert.IsTrue( + FilteredTravelRequest.IsEmpty(), + StrSubstNo(ApproverFilterUnexpectedRequestErr, + UnassignedTravelRequestHiddenMsg, FilteredTravelRequest.GetFilter("Requested For"), + DefaultTravelRequest."No.", OtherTravelRequest."No.")); + end; + + local procedure VerifyApproverFilterRangeGapSetup(FirstTravelRequest: Record "Spend Request"; LastTravelRequest: Record "Spend Request"; UnassignedTravelRequest: Record "Spend Request"; AssignedApproverNo: Code[20]; DefaultApproverNo: Code[20]) + var + ExpenseApprovalSetup: Record "Expense Approval Setup"; + ExpenseAgentSetup: Record "Expense Agent Setup"; + ExpenseUser: Record "Expense User"; + begin + Assert.AreEqual('TR-A', FirstTravelRequest."Requested For", 'The first request must use the lower range endpoint.'); + Assert.AreEqual('TR-C', LastTravelRequest."Requested For", 'The last request must use the upper range endpoint.'); + Assert.AreEqual('TR-B', UnassignedTravelRequest."Requested For", 'The unassigned request must lie between the assigned users.'); + ExpenseApprovalSetup.Get(FirstTravelRequest."Requested For"); + Assert.AreEqual(AssignedApproverNo, ExpenseApprovalSetup."Approver No.", 'The first user must be explicitly assigned.'); + ExpenseApprovalSetup.Get(LastTravelRequest."Requested For"); + Assert.AreEqual(AssignedApproverNo, ExpenseApprovalSetup."Approver No.", 'The last user must have the same explicit approver.'); + Assert.IsFalse(ExpenseApprovalSetup.Get(UnassignedTravelRequest."Requested For"), 'The middle user must have no approval setup row.'); + ExpenseUser.Get(UnassignedTravelRequest."Requested For"); + ExpenseUser.CalcFields("Approver No."); + Assert.AreEqual('', ExpenseUser."Approver No.", 'The middle user must use the default approver fallback.'); + ExpenseAgentSetup.Get(); + Assert.AreEqual(DefaultApproverNo, ExpenseAgentSetup."Default Approver No.", 'The middle user must belong to the other default approver.'); + Assert.AreNotEqual(AssignedApproverNo, DefaultApproverNo, 'The explicit and default approvers must differ.'); + ExpenseApprovalSetup.SetRange("Expense User No.", FirstTravelRequest."Requested For", LastTravelRequest."Requested For"); + Assert.AreEqual(2, ExpenseApprovalSetup.Count(), 'Only the two assigned setup rows may exist in the tested range.'); + end; + + local procedure VerifyApproverFilterRangeGapResults(var FilteredTravelRequest: Record "Spend Request"; FirstTravelRequestNo: Code[20]; LastTravelRequestNo: Code[20]; UnassignedTravelRequestNo: Code[20]) + begin + FilteredTravelRequest.SetRange("No.", FirstTravelRequestNo); + Assert.IsFalse( + FilteredTravelRequest.IsEmpty(), + StrSubstNo(ApproverFilterExpectedRequestErr, + AssignedTravelRequestVisibleMsg, FilteredTravelRequest.GetFilter("Requested For"), FirstTravelRequestNo)); + FilteredTravelRequest.SetRange("No.", LastTravelRequestNo); + Assert.IsFalse( + FilteredTravelRequest.IsEmpty(), + StrSubstNo(ApproverFilterExpectedRequestErr, + AssignedTravelRequestVisibleMsg, FilteredTravelRequest.GetFilter("Requested For"), LastTravelRequestNo)); + FilteredTravelRequest.SetRange("No.", UnassignedTravelRequestNo); + Assert.IsTrue( + FilteredTravelRequest.IsEmpty(), + StrSubstNo(ApproverFilterUnexpectedRequestErr, + UnassignedTravelRequestHiddenMsg, FilteredTravelRequest.GetFilter("Requested For"), + FirstTravelRequestNo, UnassignedTravelRequestNo)); end; local procedure VerifyPostedTravelRequestHistory(SpendRequest: Record "Spend Request"; ExpectedPostedExpenseReportHeader: Record "Posted Expense Report Header") diff --git a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIFinanceTest.Codeunit.al b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIFinanceTest.Codeunit.al index c3d532f3176..ebcedcc041e 100644 --- a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIFinanceTest.Codeunit.al +++ b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIFinanceTest.Codeunit.al @@ -49,6 +49,12 @@ codeunit 139876 "E2E PowerBI Finance Test" PowerBIAPIEndpoints: Enum "PowerBI API Endpoints"; ResponseEmptyErr: Label 'Response should not be empty.'; + local procedure Initialize() + begin + LibGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + [Test] procedure TestGetVendorLedgerEntry() var @@ -61,6 +67,8 @@ codeunit 139876 "E2E PowerBI Finance Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A purchase invoice is posted with vendor ledger entry and detailed vendor ledger entry LibPurch.CreatePurchaseInvoice(PurchHeader); PurchInvHeader.Get(LibPurch.PostPurchaseDocument(PurchHeader, true, true)); @@ -150,6 +158,8 @@ codeunit 139876 "E2E PowerBI Finance Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A sales invoice is posted with customer ledger entry and detailed customer ledger entry LibSales.CreateSalesInvoice(SalesHeader); SalesInvHeader.Get(LibSales.PostSalesDocument(SalesHeader, true, true)); @@ -235,6 +245,8 @@ codeunit 139876 "E2E PowerBI Finance Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A G/L account is created LibERM.CreateGLAccount(GLAccount); Commit(); @@ -273,6 +285,8 @@ codeunit 139876 "E2E PowerBI Finance Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A G/L account category is created LibERM.CreateGLAccountCategory(GLAccountCategory); Commit(); @@ -308,6 +322,8 @@ codeunit 139876 "E2E PowerBI Finance Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A G/L budget is created LibERM.CreateGLBudgetName(GLBudgetName); @@ -343,6 +359,8 @@ codeunit 139876 "E2E PowerBI Finance Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] G/L budget entries are created LibERM.CreateGLBudgetName(GLBudgetName); LibERM.CreateGLBudgetEntry(GLBudgetEntry, WorkDate(), LibERM.CreateGLAccountNo(), GLBudgetName.Name); @@ -393,6 +411,8 @@ codeunit 139876 "E2E PowerBI Finance Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] General journal lines for income statement account is posted, with one line outside the date range PowerBICoreTest.AssignAdminPermissionSet(); if not PBISetup.Get() then begin @@ -442,6 +462,8 @@ codeunit 139876 "E2E PowerBI Finance Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] General journal lines for account is posted CreateGeneralJournalBatch(GenJournalBatch, GLAccount); GLAccount."Income/Balance" := GLAccount."Income/Balance"::"Balance Sheet"; @@ -478,6 +500,8 @@ codeunit 139876 "E2E PowerBI Finance Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] G/L Account and Entry outside of the query filter are created GLAccount.Init(); GLAccount."No." := LibUtility.GenerateRandomCode20(GLAccount.FieldNo("No."), Database::"G/L Account"); diff --git a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIInventoryTest.Codeunit.al b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIInventoryTest.Codeunit.al index 4260437c799..da59de3909c 100644 --- a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIInventoryTest.Codeunit.al +++ b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIInventoryTest.Codeunit.al @@ -67,6 +67,12 @@ codeunit 139877 "E2E PowerBI Inventory Test" PowerBIAPIEndpoints: Enum "PowerBI API Endpoints"; ResponseEmptyErr: Label 'Response should not be empty.'; + local procedure Initialize() + begin + LibGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + [Test] procedure TestGetZones() var @@ -76,6 +82,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A location with multiple zones is created LibWhse.CreateFullWMSLocation(Location, 1); Zone.SetRange("Location Code", Location.Code); @@ -116,6 +124,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A bin is created LibWhse.CreateLocation(Location); LibWhse.CreateBin(Bin, Location.Code, '', '', ''); @@ -160,6 +170,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A sales order is created with multiple types of sales lines LibSales.CreateSalesOrder(SalesHeader); LibInv.CreateItemWithUnitPriceAndUnitCost( @@ -216,6 +228,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Sales lines exists outside of the query filter SalesLine.Init(); SalesLine."Type" := SalesLine.Type::Item; @@ -256,6 +270,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A purchase order is created with multiple types of purchase lines LibPurch.CreatePurchaseOrder(PurchHeader); LibInv.CreateItemWithUnitPriceAndUnitCost( @@ -312,6 +328,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Purchase lines exists outside of the query filter PurchLine.Init(); PurchLine."Type" := PurchLine.Type::Item; @@ -356,6 +374,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + UpdateSalesReceivablesSetup(); // [GIVEN] Multiple items which require replenishment, and requisition lines are created @@ -464,6 +484,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A transfer order is posted LibInv.CreateTransferHeader(TransferHeader); LibInv.CreateItem(Item); @@ -514,6 +536,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Transfer lines exists outside of the query filter TransferLine.Init(); TransferLine."Document No." := LibUtility.GenerateRandomCode20(TransferLine.FieldNo("Document No."), Database::"Transfer Line"); @@ -545,6 +569,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A service order is created with service lines LibService.CreateServiceDocumentWithItemServiceLine(ServiceHeader, ServiceHeader."Document Type"::Order); LibService.CreateServiceItem(ServiceItem, ServiceHeader."Bill-to Customer No."); @@ -595,6 +621,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Service lines exists outside of the query filter ServiceLine.Init(); ServiceLine."Document No." := LibUtility.GenerateRandomCode20(ServiceLine.FieldNo("Document No."), Database::"Service Line"); @@ -636,6 +664,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Sales and purchase documents are created and posted with item ledgers LibSales.CreateSalesOrder(SalesHeader); SalesLine.SetRange("Document Type", SalesHeader."Document Type"); @@ -714,6 +744,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Wrehouse activity lines are created LibInv.CreateItem(Item); PostWarehouseActivity(Item."No."); @@ -771,6 +803,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Warehouse entries are created; LibInv.CreateItem(Item); PostWarehouseActivity(Item."No."); @@ -854,6 +888,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Warehouse journal lines are created LibInv.CreateItem(Item1); LibInv.CreateItem(Item2); @@ -903,6 +939,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Warehouse journal lines are created LibInv.CreateItem(Item1); LibInv.CreateItem(Item2); @@ -983,6 +1021,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Value entry are posted LibInv.CreateItem(Item); LibPurch.CreatePurchHeader(PurchHeader, PurchHeader."Document Type"::Order, LibPurch.CreateVendorNo()); @@ -1040,6 +1080,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Value entry exists outside of the query filter PermissionsMock.Assign('SUPER'); if ValueEntry.FindLast() then; @@ -1071,6 +1113,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Assembly headers are created LibAssembly.CreateAssemblyOrder(AssemblyHeader, CalcDate('<+1M>', WorkDate()), '', 1); LibAssembly.CreateAssemblyOrder(AssemblyHeader2, CalcDate('<+1M>', WorkDate()), '', 1); @@ -1119,6 +1163,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Assembly header exists outside of the query filter AssemblyHeader.Init(); AssemblyHeader."Document Type" := AssemblyHeader."Document Type"::Quote; @@ -1147,6 +1193,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Assembly lines are created LibAssembly.CreateAssemblyOrder(AssemblyHeader, CalcDate('<+1M>', WorkDate()), '', LibRandom.RandIntInRange(2, 5)); AssemblyLine.SetRange("Document Type", AssemblyHeader."Document Type"::Order); @@ -1192,6 +1240,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Assembly lines exist outside of the query filter AssemblyHeader.Init(); AssemblyHeader."Document Type" := AssemblyHeader."Document Type"::Order; @@ -1229,6 +1279,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Job planning lines are created LibInv.CreateItem(Item1); LibInv.CreateItem(Item2); @@ -1281,6 +1333,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Job planning line exists outside of the query filter JobPlanningLine.Init(); @@ -1325,6 +1379,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Production order lines are created LibManufacturing.CreateItemManufacturing( Item, @@ -1388,6 +1444,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Production order line exists outside of the query filter ProdOrderLine.Init(); ProdOrderLine.Status := ProdOrderLine.Status::Finished; @@ -1420,6 +1478,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Production order component lines are created LibManufacturing.CreateItemManufacturing( Item, @@ -1486,6 +1546,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Production order component line exists outside of the query filter ProdOrderComp.Init(); ProdOrderComp.Status := ProdOrderComp.Status::Finished; @@ -1519,6 +1581,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Planning component lines are created #pragma warning disable AA0210 ReqWkshTemplate.SetRange(Type, ReqWkshTemplate.Type::"Req."); @@ -1573,6 +1637,8 @@ codeunit 139877 "E2E PowerBI Inventory Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Planning component line exists outside of the query filter PlanningComponent.Init(); PlanningComponent."Worksheet Template Name" := LibUtility.GenerateRandomCode(PlanningComponent.FieldNo("Worksheet Template Name"), Database::"Planning Component"); diff --git a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIManufacturingTest.Codeunit.al b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIManufacturingTest.Codeunit.al index 33ae983a5bb..e9d9e761a9c 100644 --- a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIManufacturingTest.Codeunit.al +++ b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIManufacturingTest.Codeunit.al @@ -51,6 +51,12 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" PowerBIAPIEndpoints: Enum "PowerBI API Endpoints"; ResponseEmptyErr: Label 'Response should not be empty.'; + local procedure Initialize() + begin + LibGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + [Test] procedure TestInventoryAdjmtEntries() var @@ -62,6 +68,7 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" Response: Text; Index: Integer; begin + Initialize(); // [GIVEN] Inventory Adjmt. entries are created @@ -131,6 +138,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" Response: Text; Index: Integer; begin + Initialize(); + // [GIVEN] Calendar entries are created LibManufacturing.CreateWorkCenterWithCalendar(WorkCenter); CalendarEntry.SetRange("No.", WorkCenter."No."); @@ -178,6 +187,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Machine centers are created LibManufacturing.CreateWorkCenter(WorkCenter); LibManufacturing.CreateMachineCenter(MachineCenter, WorkCenter."No.", 1); @@ -220,6 +231,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Work centers are created LibManufacturing.CreateWorkCenterGroup(WorkCenterGroup); LibManufacturing.CreateWorkCenter(WorkCenter); @@ -268,6 +281,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Production order lines are created LibManufacturing.CreateItemManufacturing( Item, @@ -342,6 +357,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Production order components are created LibManufacturing.CreateItemManufacturing( Item, @@ -416,6 +433,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Production order routing lines are created LibInv.CreateItem(Item); CreateRoutingForItem(Item); @@ -496,6 +515,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Item is created with production BOM and routing LibManufacturing.CreateItemManufacturing( Item, @@ -569,6 +590,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Item ledger entries exist outside of the query filter PermissionsMock.Assign('SUPER'); if ItemLedgerEntry.FindLast() then; @@ -612,6 +635,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Item is created with routing LibManufacturing.CreateItemManufacturing( Item, @@ -702,6 +727,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" Response: Text; Index: Integer; begin + Initialize(); + // [GIVEN] Item is created with routing LibManufacturing.CreateItemManufacturing( Item, @@ -839,6 +866,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] "Show Capacity In" is set in Manufacturing Setup LibManufacturing.CreateCapacityUnitOfMeasure(CapacityUnitOfMeasure, Enum::"Capacity Unit of Measure"::Minutes); ManufacturingSetup.Get(); @@ -877,6 +906,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Production orders are created LibManufacturing.CreateItemManufacturing( Item, @@ -937,6 +968,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Routing links are created LibManufacturing.CreateRoutingLink(RoutingLink); @@ -974,6 +1007,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Routing headers are created LibManufacturing.CreateRoutingHeader(RoutingHeader, RoutingHeader.Type::Parallel); LibManufacturing.CreateRoutingHeader(RoutingHeader, RoutingHeader.Type::Serial); @@ -1014,6 +1049,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Work center groups are created LibManufacturing.CreateWorkCenterGroup(WorkCenterGroup); LibManufacturing.CreateWorkCenterGroup(WorkCenterGroup); @@ -1059,6 +1096,8 @@ codeunit 139878 "E2E PowerBI Manufacturing Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Manufacturing value entries are created LibManufacturing.CreateItemManufacturing( Item, diff --git a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIProjectTest.Codeunit.al b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIProjectTest.Codeunit.al index 5a71e714459..7b67a7dc12d 100644 --- a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIProjectTest.Codeunit.al +++ b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIProjectTest.Codeunit.al @@ -38,6 +38,12 @@ codeunit 139879 "E2E PowerBI Project Test" PowerBIEndpoints: Enum "PowerBI API Endpoints"; ResponseEmptyErr: Label 'Response should not be empty.'; + local procedure Initialize() + begin + LibGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + [Test] procedure TestGetJobs() var @@ -47,6 +53,8 @@ codeunit 139879 "E2E PowerBI Project Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Jobs are created LibJob.CreateJob(Job); Job.Validate("Starting Date", WorkDate()); @@ -108,6 +116,8 @@ codeunit 139879 "E2E PowerBI Project Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Job tasks are created LibJob.CreateJob(Job); LibJob.CreateJobTask(Job, JobTask); @@ -154,6 +164,8 @@ codeunit 139879 "E2E PowerBI Project Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Job planning lines are created LibJob.CreateJob(Job); LibJob.CreateJobTask(Job, JobTask); @@ -217,6 +229,8 @@ codeunit 139879 "E2E PowerBI Project Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Job ledger entries are posted LibJob.CreateJob(Job); LibJob.CreateJobTask(Job, JobTask); @@ -283,6 +297,8 @@ codeunit 139879 "E2E PowerBI Project Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Purchase order is created with outstanding lines LibJob.CreateJob(Job); CreatePOWithJob(PurchHeader, Job); @@ -335,6 +351,8 @@ codeunit 139879 "E2E PowerBI Project Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Purchase lines exist outside of the query filter PurchHeader.Init(); PurchHeader."Document Type" := PurchHeader."Document Type"::Invoice; @@ -399,6 +417,8 @@ codeunit 139879 "E2E PowerBI Project Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Purchase order is created with received not invoiced lines LibJob.CreateJob(Job); CreatePOWithJob(PurchHeader, Job); diff --git a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIPurchasesTest.Codeunit.al b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIPurchasesTest.Codeunit.al index 51e3fa3b43f..dde930c1758 100644 --- a/src/Apps/W1/PowerBIReports/Test/E2EPowerBIPurchasesTest.Codeunit.al +++ b/src/Apps/W1/PowerBIReports/Test/E2EPowerBIPurchasesTest.Codeunit.al @@ -43,6 +43,12 @@ codeunit 139880 "E2E PowerBI Purchases Test" PowerBIAPIEndpoints: Enum "PowerBI API Endpoints"; ResponseEmptyErr: Label 'Response should not be empty.'; + local procedure Initialize() + begin + LibGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + [Test] procedure TestGetOutstandingPurchOrderLine() var @@ -53,6 +59,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] An outstanding purchase order with multiple lines exists LibPurch.CreatePurchaseOrder(PurchHeader); LibInv.CreateItemWithUnitPriceAndUnitCost( @@ -88,6 +96,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Purchase lines exist outside of the query filter PurchHeader."Document Type" := PurchHeader."Document Type"::Invoice; PurchHeader."No." := LibUtility.GenerateRandomCode20(PurchHeader.FieldNo("No."), Database::"Purchase Header"); @@ -151,6 +161,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] An item budget entry exists LibERM.CreateItemBudgetName(ItemBudgetName, "Analysis Area Type"::Purchase); LibInv.CreateItemBudgetEntry( @@ -198,6 +210,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Item budget entries exist outside of the query filter if ItemBudgetEntry.FindLast() then; ItemBudgetEntry."Entry No." += 1; @@ -228,6 +242,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A purchase order is posted with item ledger entry and value entry LibPurch.CreatePurchaseOrder(PurchaseHeader); PurchaseHeader.Validate("Payment Discount %", 3); @@ -289,6 +305,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Value entries exist outside of the query filter PermissionsMock.Assign('SUPER'); if ItemLedgerEntry.FindLast() then; @@ -330,6 +348,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] A purchase order with multiple lines is received but not invoiced LibPurch.CreatePurchaseOrder(PurchaseHeader); LibInv.CreateItemWithUnitPriceAndUnitCost( @@ -386,6 +406,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Purchase lines exist outside of the query filter PurchaseHeader."Document Type" := PurchaseHeader."Document Type"::Invoice; PurchaseHeader."No." := LibUtility.GenerateRandomCode20(PurchaseHeader.FieldNo("No."), Database::"Purchase Header"); @@ -457,6 +479,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" Response: Text; GLAccountCode: Code[20]; begin + Initialize(); + // [GIVEN] A purchase order with multiple lines for item, G/L account & resource. LibPurch.CreatePurchaseOrder(PurchaseHeader); PurchaseHeader."Posting Date" := WorkDate(); @@ -557,6 +581,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" GLAccountCode: Code[20]; PurchInvoiceNo: Code[20]; begin + Initialize(); + // [GIVEN] A purchase invoice with multiple lines for G/L and Resource LibPurch.CreatePurchaseInvoice(PurchaseHeader); @@ -634,6 +660,8 @@ codeunit 139880 "E2E PowerBI Purchases Test" GLAccountCode: Code[20]; PurchCrMemoNo: Code[20]; begin + Initialize(); + // [GIVEN] A purchase credit memo with multiple lines for G/L and Resource LibPurch.CreatePurchaseCreditMemo(PurchaseHeader); diff --git a/src/Apps/W1/PowerBIReports/Test/E2EPowerBISalesTest.Codeunit.al b/src/Apps/W1/PowerBIReports/Test/E2EPowerBISalesTest.Codeunit.al index 80e1f147332..5a8912da008 100644 --- a/src/Apps/W1/PowerBIReports/Test/E2EPowerBISalesTest.Codeunit.al +++ b/src/Apps/W1/PowerBIReports/Test/E2EPowerBISalesTest.Codeunit.al @@ -53,6 +53,9 @@ codeunit 139881 "E2E PowerBI Sales Test" if IsInitialized then exit; + LibGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; Commit(); end; diff --git a/src/Apps/W1/Quality Management/test/src/QltyTestsInspectionsAPI.Codeunit.al b/src/Apps/W1/Quality Management/test/src/QltyTestsInspectionsAPI.Codeunit.al index b2a38ac3f7b..66004d3ce71 100644 --- a/src/Apps/W1/Quality Management/test/src/QltyTestsInspectionsAPI.Codeunit.al +++ b/src/Apps/W1/Quality Management/test/src/QltyTestsInspectionsAPI.Codeunit.al @@ -50,6 +50,9 @@ codeunit 139972 "Qlty. Tests - Inspections API" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.CreateVATData(); IsInitialized := true; Commit(); diff --git a/src/Apps/W1/Sustainability/test/src/PowerBISustainabilityTest.Codeunit.al b/src/Apps/W1/Sustainability/test/src/PowerBISustainabilityTest.Codeunit.al index e91d24174c6..c349a727223 100644 --- a/src/Apps/W1/Sustainability/test/src/PowerBISustainabilityTest.Codeunit.al +++ b/src/Apps/W1/Sustainability/test/src/PowerBISustainabilityTest.Codeunit.al @@ -31,6 +31,12 @@ codeunit 148215 "PowerBI Sustainability Test" FieldHiddenMsg: Label '''%1'' field should be hidden.', Comment = '%1 - field caption'; FieldShownMsg: Label '''%1'' field should be shown.', Comment = '%1 - field caption'; + local procedure Initialize() + begin + LibGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + [Test] procedure TestSustainLedgerEntry() var @@ -38,6 +44,8 @@ codeunit 148215 "PowerBI Sustainability Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Insert a Sustainability Ledger Entry SustainabilityLedgerEntry.Init(); SustainabilityLedgerEntry."Account No." := LibUtility.GenerateGUID(); @@ -103,6 +111,8 @@ codeunit 148215 "PowerBI Sustainability Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Insert a Sustainability Ledger Entry EmployeeLedgerEntry.Init(); DetailEmployLedgEntry.Init(); @@ -159,6 +169,8 @@ codeunit 148215 "PowerBI Sustainability Test" TargetURL: Text; Response: Text; begin + Initialize(); + // [GIVEN] Insert a Sustainability Goal if not UserSetup.Get(UserId()) then begin diff --git a/src/Apps/W1/Sustainability/test/src/SustainabilityAPITests.Codeunit.al b/src/Apps/W1/Sustainability/test/src/SustainabilityAPITests.Codeunit.al index 8c0064704ab..c29a972b139 100644 --- a/src/Apps/W1/Sustainability/test/src/SustainabilityAPITests.Codeunit.al +++ b/src/Apps/W1/Sustainability/test/src/SustainabilityAPITests.Codeunit.al @@ -275,6 +275,9 @@ codeunit 148185 "Sustainability API Tests" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibrarySustainability.CleanUpBeforeTesting(); IsInitialized := true; diff --git a/src/DisabledTests/E-Document_Core_Tests/E-Document Core Tests.DisabledTest.json b/src/DisabledTests/E-Document_Core_Tests/E-Document Core Tests.DisabledTest.json index 2a0b6b498c3..1db9a8feddd 100644 --- a/src/DisabledTests/E-Document_Core_Tests/E-Document Core Tests.DisabledTest.json +++ b/src/DisabledTests/E-Document_Core_Tests/E-Document Core Tests.DisabledTest.json @@ -314,11 +314,6 @@ "codeunitName": "EDocCopilotPOGeneralHarms", "method": "*" }, - { - "codeunitId": 135575, - "codeunitName": "E-Doc. API Test", - "method": "*" - }, { "codeunitId": 139235, "codeunitName": "PEPPOL30 Management Tests", diff --git a/src/DisabledTests/Expense_Agent_Tests/Expense_Agent_Tests.DisabledTest.json b/src/DisabledTests/Expense_Agent_Tests/Expense_Agent_Tests.DisabledTest.json index b23129476de..02c2392f10b 100644 --- a/src/DisabledTests/Expense_Agent_Tests/Expense_Agent_Tests.DisabledTest.json +++ b/src/DisabledTests/Expense_Agent_Tests/Expense_Agent_Tests.DisabledTest.json @@ -1,254 +1,4 @@ [ - { - "codeunitId": 148315, - "codeunitName": "Expense Users API Test", - "method": "EmployeesAPICanFilterExpenseUsers" - }, - { - "codeunitId": 148315, - "codeunitName": "Expense Users API Test", - "method": "UnlinkedExpenseUserIsHiddenFromAPI" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelersAPIMapsEmployeeNumberToExpenseUser" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelersAPIRejectsEmployeeWithoutExpenseUser" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "CreateExpenseReportActionRecreatesDeletedReport" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "ApproveTravelRequestActionCreatesExpenseReport" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelRequestsAPINormalizesCurrency" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelRequestDetailsAPINormalizesCurrency" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelRequestsAPIPreservesAndUpdatesDates" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelRequestsAreScopedByEmployeeNumber" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "ExpenseReportAPIExposesLinkedTravelRequest" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelRequestDetailsAPIExposesTypeAndCategory" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "ApproverViewReturnsOnlyAssignedTravelRequests" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelRequestsAPIAllowsOwnerOnInsertAndUnchangedPatch" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelRequestsAPIRejectsLifecycleFieldChanges" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "TravelRequestsAPIRejectsRequestedForChange" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "LegacySpendRequestsAPIAllowsUnchangedOwner" - }, - { - "codeunitId": 148347, - "codeunitName": "Travel Requests API Test", - "method": "LegacySpendRequestsAPIRejectsTravelRequestOwnerChange" - }, - { - "codeunitId": 148318, - "codeunitName": "Expense Capabilities API Test", - "method": "CapabilitiesProjectsEnabledViaAPI" - }, - { - "codeunitId": 148318, - "codeunitName": "Expense Capabilities API Test", - "method": "CapabilitiesProjectsDisabledViaAPI" - }, - { - "codeunitId": 148318, - "codeunitName": "Expense Capabilities API Test", - "method": "CapabilitiesConsolidatedProjectsFollowsProjectFieldsViaAPI" - }, - { - "codeunitId": 148318, - "codeunitName": "Expense Capabilities API Test", - "method": "ActivityLogCapabilityEnabledViaAPI" - }, - { - "codeunitId": 148318, - "codeunitName": "Expense Capabilities API Test", - "method": "TravelRequestCapabilityEnabledViaAPI" - }, - { - "codeunitId": 148343, - "codeunitName": "Expense Activity Log API Test", - "method": "ActivityLogEntryIsExposedThroughReadOnlyAPI" - }, - { - "codeunitId": 148343, - "codeunitName": "Expense Activity Log API Test", - "method": "ActivityLogAPIRejectsWrites" - }, - { - "codeunitId": 148343, - "codeunitName": "Expense Activity Log API Test", - "method": "NonSnapshotActivityDoesNotExposeCurrencies" - }, - { - "codeunitId": 148343, - "codeunitName": "Expense Activity Log API Test", - "method": "UnscopedActivityAPIHidesEntries" - }, - { - "codeunitId": 148343, - "codeunitName": "Expense Activity Log API Test", - "method": "SubmitterHistoryReturnsCompleteTimelinesForSubmittedReports" - }, - { - "codeunitId": 148343, - "codeunitName": "Expense Activity Log API Test", - "method": "ApproverHistoryReturnsCompleteTimelinesForActedOnReports" - }, - { - "codeunitId": 148343, - "codeunitName": "Expense Activity Log API Test", - "method": "E2EActivityLogScenario" - }, - { - "codeunitId": 148333, - "codeunitName": "Expense Agent Setup API Test", - "method": "EmailAddressFieldIsExposedThroughAPI" - }, - { - "codeunitId": 148349, - "codeunitName": "Expense PerDiem Locations Test", - "method": "PerDiemLocationsReturnsLinkedLocationViaAPI" - }, - { - "codeunitId": 148349, - "codeunitName": "Expense PerDiem Locations Test", - "method": "PerDiemLocationsExcludesNonPerDiemCategoryViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "AssignedByPersonResponsibleReturnsWholeProjectViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "AssignedByProjectManagerReturnsWholeProjectViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "AssignedByProjectLevelResourceReturnsWholeProjectViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "AssignedByTaskLevelResourceReturnsOnlyThatTaskViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "AssignedByPlanningLineReturnsOnlyThatTaskViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "WholeProjectSignalSupersedesTaskLevelViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "OverlappingSignalsForSameResourceAreDeduplicatedViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "CompletedProjectExcludedEvenWhenAssignedViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "EmptyResourceUserMatchesNothingViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "BlankUserIdDoesNotMatchBlankProjectManagerViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "ProjectManagerMatchWithBlankResourceReturnsProjectViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "TasklessProjectExcludedViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "WholeProjectAndTaskLevelAcrossProjectsNoLeakageViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "AllProjectsVisibilityReturnsAllProjectsViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "AllProjectsVisibilityIncludesActiveStatusesAndPostingTasksViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "AssignedProjectsRequiresScopeFilterViaAPI" - }, - { - "codeunitId": 148331, - "codeunitName": "Expense Projects API Test", - "method": "AssignedProjectsBlockedWhenProjectFieldsDisabledViaAPI" - }, { "codeunitId": 148305, "codeunitName": "Expense Test", @@ -293,10 +43,5 @@ "codeunitId": 148319, "codeunitName": "Cancel Posted Exp. Report Test", "method": "CancelMultiLineReportGeneratesNewTransactionNoForReversedLines" - }, - { - "codeunitId": 148348, - "codeunitName": "Expense VAT Spec. API Test", - "method": "AgentVATSpecificationIsInsertedThroughAPI" } ] diff --git a/src/DisabledTests/_Exclude_APIV1__Tests/_Exclude_APIV1__Tests.DisabledTest.json b/src/DisabledTests/_Exclude_APIV1__Tests/_Exclude_APIV1__Tests.DisabledTest.json index ad692000a56..bcca968fa42 100644 --- a/src/DisabledTests/_Exclude_APIV1__Tests/_Exclude_APIV1__Tests.DisabledTest.json +++ b/src/DisabledTests/_Exclude_APIV1__Tests/_Exclude_APIV1__Tests.DisabledTest.json @@ -1,84 +1,4 @@ [ - { - "codeunitId": 139701, - "codeunitName": "APIV1 - Accounts E2E", - "method": "TestGetAccounts" - }, - { - "codeunitId": 139704, - "codeunitName": "APIV1 - Payment Terms E2E", - "method": "TestGetPaymentTerms" - }, - { - "codeunitId": 139705, - "codeunitName": "APIV1 - Shipment Methods E2E", - "method": "TestGetShipmentMethods" - }, - { - "codeunitId": 139706, - "codeunitName": "APIV1 - Company Info. E2E", - "method": "TestGetCompanyInformationWithComplexType" - }, - { - "codeunitId": 139706, - "codeunitName": "APIV1 - Company Info. E2E", - "method": "TestModifyCompanyInformation" - }, - { - "codeunitId": 139706, - "codeunitName": "APIV1 - Company Info. E2E", - "method": "TestModifyCompanyInformationWithComplexType" - }, - { - "codeunitId": 139706, - "codeunitName": "APIV1 - Company Info. E2E", - "method": "TestRemoveComplexTypeFromCompanyInformation" - }, - { - "codeunitId": 139707, - "codeunitName": "APIV1 - Item Categories E2E", - "method": "TestCreateItemCategory" - }, - { - "codeunitId": 139707, - "codeunitName": "APIV1 - Item Categories E2E", - "method": "TestDeleteItemCategory" - }, - { - "codeunitId": 139707, - "codeunitName": "APIV1 - Item Categories E2E", - "method": "TestGetItemCategories" - }, - { - "codeunitId": 139707, - "codeunitName": "APIV1 - Item Categories E2E", - "method": "TestModifyItemCategory" - }, - { - "codeunitId": 139708, - "codeunitName": "Tax Groups E2E", - "method": "TestCreateTaxGroup" - }, - { - "codeunitId": 139708, - "codeunitName": "Tax Groups E2E", - "method": "TestDeleteTaxGroup" - }, - { - "codeunitId": 139708, - "codeunitName": "Tax Groups E2E", - "method": "TestGetTaxGroup" - }, - { - "codeunitId": 139708, - "codeunitName": "Tax Groups E2E", - "method": "TestGetTaxGroups" - }, - { - "codeunitId": 139708, - "codeunitName": "Tax Groups E2E", - "method": "TestModifyTaxGroup" - }, { "codeunitId": 139709, "codeunitName": "Sales Invoices E2E", @@ -89,1369 +9,124 @@ "codeunitName": "Sales Invoices E2E", "method": "TestActionCancelInvoice" }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestActionMakeCorrectiveCreditMemo" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestActionPostAndSendInvoice" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestActionPostInvoice" - }, { "codeunitId": 139709, "codeunitName": "Sales Invoices E2E", "method": "TestActionSendCancelledInvoice" }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestActionSendDraftInvoice" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestActionSendPostedInvoice" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestClearingManualDiscounts" - }, { "codeunitId": 139709, "codeunitName": "Sales Invoices E2E", "method": "TestCreateInvoiceThroughPageAndAPI" }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestDeleteInvoice" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestEmptyModifyInvoices" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestGetInvoices" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestGetInvoicesAppliesDiscountPct" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestGetInvoicesRedistributesDiscountAmt" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestModifyingWithBlankIdEmptiesTheCodeAndTheId" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestModifyInvoiceNumberForDraftInvoice" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestModifyInvoices" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestModifyInvoiceSetManualDiscount" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestPartialModifyInvoices" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestPostInvoices" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestPostInvoiceWithCurrency" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestPostInvoiceWithDates" - }, - { - "codeunitId": 139709, - "codeunitName": "Sales Invoices E2E", - "method": "TestPostInvoiceWithEmail" - }, - { - "codeunitId": 139710, - "codeunitName": "Countries/Regions E2E", - "method": "TestCreateCountriesRegions" - }, - { - "codeunitId": 139710, - "codeunitName": "Countries/Regions E2E", - "method": "TestDeleteCountriesRegions" - }, - { - "codeunitId": 139710, - "codeunitName": "Countries/Regions E2E", - "method": "TestGetCountriesRegions" - }, - { - "codeunitId": 139710, - "codeunitName": "Countries/Regions E2E", - "method": "TestModifyCountriesRegions" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestActionShipAndInvoice" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestClearingManualDiscounts" - }, { "codeunitId": 139711, "codeunitName": "APIV1 - Sales Orders E2E", "method": "TestCreateOrderThroughPageAndAPI" }, { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestDeleteOrders" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestEmptyModifyOrders" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestGetOrders" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestGetOrdersAppliesDiscountPct" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestGetOrdersRedistributesDiscountAmt" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestModifyOrders" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestModifyOrderSetManualDiscount" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestPartialModifyOrders" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestPostOrderForCustomerWithLocationCode" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestPostOrders" - }, - { - "codeunitId": 139711, - "codeunitName": "APIV1 - Sales Orders E2E", - "method": "TestPostOrderWithCurrency" - }, - { - "codeunitId": 139712, - "codeunitName": "APIV1 - UofM E2E", - "method": "TestDeleteUnitOfMeasure" - }, - { - "codeunitId": 139712, - "codeunitName": "APIV1 - UofM E2E", - "method": "TestGetUnitOfMeasure" - }, - { - "codeunitId": 139712, - "codeunitName": "APIV1 - UofM E2E", - "method": "TestInsertUnitOfMeasure" - }, - { - "codeunitId": 139712, - "codeunitName": "APIV1 - UofM E2E", - "method": "TestModifyUnitOfMeasure" - }, - { - "codeunitId": 139713, - "codeunitName": "APIV1 - Currencies E2E", - "method": "TestCreateCurrency" - }, - { - "codeunitId": 139713, - "codeunitName": "APIV1 - Currencies E2E", - "method": "TestDeleteCurrency" - }, - { - "codeunitId": 139713, - "codeunitName": "APIV1 - Currencies E2E", - "method": "TestGetCurrencies" - }, - { - "codeunitId": 139713, - "codeunitName": "APIV1 - Currencies E2E", - "method": "TestModifyCurrency" + "codeunitId": 139723, + "codeunitName": "APIV1 - Sales Quotes E2E", + "method": "TestActionMakeOrderFromQuote" }, { - "codeunitId": 139714, - "codeunitName": "Payment Methods E2E", - "method": "TestCreatePaymentMethods" + "codeunitId": 139723, + "codeunitName": "APIV1 - Sales Quotes E2E", + "method": "TestCreateQuoteThroughPageAndAPI" }, { - "codeunitId": 139714, - "codeunitName": "Payment Methods E2E", - "method": "TestDeletePaymentMethods" + "codeunitId": 139728, + "codeunitName": "APIV1 - Sales Credit Memos E2E", + "method": "TestActionCancelAndSendCorrectiveCreditMemo" }, { - "codeunitId": 139714, - "codeunitName": "Payment Methods E2E", - "method": "TestGetPaymentMethods" + "codeunitId": 139728, + "codeunitName": "APIV1 - Sales Credit Memos E2E", + "method": "TestActionCancelCorrectiveCreditMemo" }, { - "codeunitId": 139714, - "codeunitName": "Payment Methods E2E", - "method": "TestModifyPaymentMethods" + "codeunitId": 139728, + "codeunitName": "APIV1 - Sales Credit Memos E2E", + "method": "TestCreateCreditMemoThroughPageAndAPI" }, { - "codeunitId": 139715, - "codeunitName": "APIV1 - Balance Sheet E2E", - "method": "TestGetBalanceSheetRecords" + "codeunitId": 139729, + "codeunitName": "APIV1 - Purchase Invoices E2E", + "method": "TestPurchaseInvoiceWithPaymentDiscount" }, { - "codeunitId": 139716, - "codeunitName": "APIV1 - Income Statement E2E", - "method": "TestGetIncomeStatementRecords" + "codeunitId": 139734, + "codeunitName": "APIV1 - Sales Inv. Lines E2E", + "method": "TestGettingLinesWithDifferentTypes" }, { - "codeunitId": 139717, - "codeunitName": "APIV1 - CashFlow Statement E2E", - "method": "TestGetCashFlowRecords" + "codeunitId": 139734, + "codeunitName": "APIV1 - Sales Inv. Lines E2E", + "method": "TestPatchingTheIdToItemChangesLineType" }, { - "codeunitId": 139718, - "codeunitName": "APIV1 - Trial Balance E2E", - "method": "TestGetTrialBalanceRecords" + "codeunitId": 139735, + "codeunitName": "APIV1 - Sales Order Lines E2E", + "method": "TestGettingLinesWithDifferentTypes" }, { - "codeunitId": 139719, - "codeunitName": "APIV1 - Aged AP E2E", - "method": "TestGetAgedAPRecords" + "codeunitId": 139735, + "codeunitName": "APIV1 - Sales Order Lines E2E", + "method": "TestPatchingTheIdToItemChangesLineType" }, { - "codeunitId": 139720, - "codeunitName": "APIV1 - Aged AR E2E", - "method": "TestGetAgedARRecords" + "codeunitId": 139739, + "codeunitName": "APIV1 - Item Variants E2E", + "method": "TestDeleteInUse" }, { - "codeunitId": 139721, - "codeunitName": "APIV1 - Ret. Earnings E2E", - "method": "TestRetainedEarningsStatementRecords" + "codeunitId": 139734, + "codeunitName": "APIV1 - Sales Inv. Lines E2E", + "method": "TestPostingBlankLineDefaultsToItemType" }, { - "codeunitId": 139722, - "codeunitName": "APIV1 - Employees E2E", - "method": "TestCreateEmployee" + "codeunitId": 139735, + "codeunitName": "APIV1 - Sales Order Lines E2E", + "method": "TestPostingBlankLineDefaultsToItemType" }, { - "codeunitId": 139722, - "codeunitName": "APIV1 - Employees E2E", - "method": "TestDeleteEmployee" + "codeunitId": 139736, + "codeunitName": "APIV1 - Sales Quote Lines E2E", + "method": "TestPostingBlankLineDefaultsToItemType" }, { - "codeunitId": 139722, - "codeunitName": "APIV1 - Employees E2E", - "method": "TestGetEmployee" + "codeunitId": 139737, + "codeunitName": "APIV1 - Sales CrMemo Lines E2E", + "method": "TestPostingBlankLineDefaultsToItemType" }, { - "codeunitId": 139722, - "codeunitName": "APIV1 - Employees E2E", - "method": "TestModifyEmployee" + "codeunitId": 139738, + "codeunitName": "APIV1 - Purchase Inv Lines E2E", + "method": "TestPostingBlankLineDefaultsToItemType" }, { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestActionMakeInvoiceFromQuote" + "codeunitId": 139731, + "codeunitName": "APIV1 - Automation RS Package", + "method": "TestImportRSPackage" }, { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestActionMakeOrderFromQuote" + "codeunitId": 139731, + "codeunitName": "APIV1 - Automation RS Package", + "method": "TestImportWrongRSPackage" }, { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestActionSendQuote" + "codeunitId": 139731, + "codeunitName": "APIV1 - Automation RS Package", + "method": "TestApplyRSPackage" }, { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestClearingManualDiscounts" + "codeunitId": 139730, + "codeunitName": "APIV1 - GLEntries E2E", + "method": "TestGetGLEntries" }, { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestCreateQuoteThroughPageAndAPI" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestDeleteQuotes" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestEmptyModifyQuotes" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestGetQuotes" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestGetQuotesAppliesDiscountPct" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestGetQuotesRedistributesDiscountAmt" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestModifyQuotes" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestModifyQuoteSetManualDiscount" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestPartialModifyQuotes" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestPostQuotes" - }, - { - "codeunitId": 139723, - "codeunitName": "APIV1 - Sales Quotes E2E", - "method": "TestPostQuoteWithCurrency" - }, - { - "codeunitId": 139724, - "codeunitName": "APIV1 - Dimensions E2E", - "method": "TestGetDimensions" - }, - { - "codeunitId": 139724, - "codeunitName": "APIV1 - Dimensions E2E", - "method": "TestGetDimensionValues" - }, - { - "codeunitId": 139727, - "codeunitName": "APIV1 - Journals E2E", - "method": "TestActionPostGenJournalBatch" - }, - { - "codeunitId": 139727, - "codeunitName": "APIV1 - Journals E2E", - "method": "TestCreateJournal" - }, - { - "codeunitId": 139727, - "codeunitName": "APIV1 - Journals E2E", - "method": "TestDeleteJournal" - }, - { - "codeunitId": 139727, - "codeunitName": "APIV1 - Journals E2E", - "method": "TestGetJournals" - }, - { - "codeunitId": 139727, - "codeunitName": "APIV1 - Journals E2E", - "method": "TestModifyJournal" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestActionCancelAndSendCorrectiveCreditMemo" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestActionCancelCorrectiveCreditMemo" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestActionPostAndSendCreditMemo" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestActionPostCreditMemo" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestActionSendCancelledCreditMemo" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestActionSendPostedCreditMemo" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestClearingManualDiscounts" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestCreateCreditMemoThroughPageAndAPI" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestDeleteCreditMemo" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestEmptyModifyCreditMemos" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestGetCreditMemos" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestGetCreditMemosAppliesDiscountPct" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestGetCreditMemosRedistributesDiscountAmt" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestModifyCreditMemos" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestModifyCreditMemoSetManualDiscount" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestPartialModifyCreditMemos" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestPostCreditMemos" - }, - { - "codeunitId": 139728, - "codeunitName": "APIV1 - Sales Credit Memos E2E", - "method": "TestPostCreditMemoWithCurrency" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestActionPostPurchaseInvoice" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestCreateInvoiceThroughPageAndAPI" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestDeleteInvoice" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestEmptyModifyInvoices" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestGetInvoices" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestModifyInvoices" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestPartialModifyInvoices" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestPostInvoices" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestPostPurchaseInvoiceWithCurrency" - }, - { - "codeunitId": 139729, - "codeunitName": "APIV1 - Purchase Invoices E2E", - "method": "TestPurchaseInvoiceWithPaymentDiscount" - }, - { - "codeunitId": 139730, - "codeunitName": "APIV1 - GLEntries E2E", - "method": "TestGetGLEntries" - }, - { - "codeunitId": 139731, - "codeunitName": "APIV1 - Automation RS Package", - "method": "TestApplyRSPackage" - }, - { - "codeunitId": 139731, - "codeunitName": "APIV1 - Automation RS Package", - "method": "TestCreateRSPackage" - }, - { - "codeunitId": 139731, - "codeunitName": "APIV1 - Automation RS Package", - "method": "TestImportRSPackage" - }, - { - "codeunitId": 139731, - "codeunitName": "APIV1 - Automation RS Package", - "method": "TestImportWrongRSPackage" - }, - { - "codeunitId": 139731, - "codeunitName": "APIV1 - Automation RS Package", - "method": "TestUploadRSPackageFile" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestCreateDraftInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestCreateDraftPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestCreateGLEntryAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestCreateJournalLineAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestCreatePostedInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestCreatePostedPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestCreateQuoteAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestDeleteDraftInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestDeleteDraftPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestDeleteGLEntryAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestDeleteJournalLineAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestDeletePostedInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestDeletePostedPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestDeleteQuoteAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetDraftInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetDraftInvoiceAttachments" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetDraftPurchaseInvoiceAttachments" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetGLEntryAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetGLEntryAttachments" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetJournalAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetJournalLineAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetJournalLineAttachments" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetPostedInvoiceAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetPostedInvoiceAttachments" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetPostedPurchaseInvoiceAttachments" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetQuoteAttachment" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestGetQuoteAttachments" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestLinkedAttachmentContentChangeKeepsOtherFieldsUnchanged" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestLinkedAttachmentDocumentIdChangeNotAllowed" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestLinkedAttachmentFileNameChangeKeepsOtherFieldsUnchanged" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestLinkedAttachmentIdChangeNotAllowed" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestTransferAttachmentFromDraftToPostedInvoice" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestTransferAttachmentFromDraftToPostedPurchaseInvoice" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestUpdateGenJournalLineAttachmentBinaryContent" - }, - { - "codeunitId": 139733, - "codeunitName": "APIV1 - Attachments E2E", - "method": "TestUpdateGLEntryAttachmentBinaryContent" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestDeleteInvoiceLine" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestDeletingLineKeepsInvoiceDiscountAmt" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestDeletingLineMovesInvoiceDiscountPct" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestDeletingLineRemovesInvoiceDiscountPct" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestGetInvoiceLineDirectly" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestGetInvoiceLines" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestGetInvoiceLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestGetPostedInvoiceLines" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestGettingLinesWithDifferentTypes" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestInsertingLineUpdatesInvoiceDiscountPct" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestModifyingLineKeepsInvoiceDiscountAmt" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestModifyingLineUpdatesInvoiceDiscountPct" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestModifyInvoiceLine" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestModifyInvoiceLineWithUoM" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestPatchingTheIdToAccountChangesLineType" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestPatchingTheIdToItemChangesLineType" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestPostingBlankLineDefaultsToItemType" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestPostInvoiceLines" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestPostInvoiceLinesWithItemVariant" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestPostInvoiceLinesWithUoM" - }, - { - "codeunitId": 139734, - "codeunitName": "APIV1 - Sales Inv. Lines E2E", - "method": "TestPostInvoiceLineWithSequence" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestDeleteOrderLine" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestDeletingLineKeepsOrderDiscountAmt" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestDeletingLineMovesOrderDiscountPct" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestDeletingLineRemovesOrderDiscountPct" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestGetOrderLineDirectly" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestGetOrderLines" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestGetOrderLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestGettingLinesWithDifferentTypes" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestInsertingLineUpdatesOrderDiscountPct" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestModifyingLineKeepsOrderDiscountAmt" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestModifyingLineUpdatesOrderDiscountPct" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestModifyOrderLines" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestPatchingTheIdToAccountChangesLineType" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestPatchingTheIdToItemChangesLineType" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestPostingBlankLineDefaultsToItemType" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestPostOrderLines" - }, - { - "codeunitId": 139735, - "codeunitName": "APIV1 - Sales Order Lines E2E", - "method": "TestPostOrderLineWithItemVariant" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestDeleteQuoteLine" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestDeletingLineKeepsQuoteDiscountAmt" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestDeletingLineMovesQuoteDiscountPct" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestDeletingLineRemovesQuoteDiscountPct" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestGetQuoteLineDirectly" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestGetQuoteLines" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestGetQuoteLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestInsertingLineKeepsQuoteDiscountAmt" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestInsertingLineUpdatesQuoteDiscountPct" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestModifyingLineKeepsQuoteDiscountAmt" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestModifyingLineUpdatesQuoteDiscountPct" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestModifyQuoteLines" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestPostingBlankLineDefaultsToItemType" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestPostQuoteLines" - }, - { - "codeunitId": 139736, - "codeunitName": "APIV1 - Sales Quote Lines E2E", - "method": "TestPostQuoteLinesWithItemVariant" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestDeleteCreditMemoLine" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestDeletePostedCreditMemoLine" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestDeletingLineKeepsCreditMemoDiscountAmt" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestDeletingLineMovesCreditMemoDiscountPct" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestDeletingLineRemovesCreditMemoDiscountPct" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestGetCreditMemoLineDirectly" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestGetCreditMemoLines" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestGetCreditMemoLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestGetPostedCreditMemoLines" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestGettingLinesWithDifferentTypes" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestInsertingLineUpdatesCreditMemoDiscountPct" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestModifyCreditMemoLines" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestModifyingLineKeepsCreditMemoDiscountAmt" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestModifyingLineUpdatesCreditMemoDiscountPct" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestPatchingTheIdToAccountChangesLineType" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestPatchingTheIdToItemChangesLineType" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestPostCreditMemoLines" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestPostCreditMemoLinesWithItemVariant" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestPostCreditMemoLineWithSequence" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestPostingBlankLineDefaultsToItemType" - }, - { - "codeunitId": 139737, - "codeunitName": "APIV1 - Sales CrMemo Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestDeleteInvoiceLine" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestDeletingLineRemovesInvoiceDiscountPct" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestGetInvoiceLineDirectly" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestGetInvoiceLines" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestGetInvoiceLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestGetPostedInvoiceLines" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestInsertingLineUpdatesInvoiceDiscountPct" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestModifyingLineUpdatesInvoiceDiscountPct" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestModifyInvoiceLines" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestPostingBlankLineDefaultsToItemType" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestPostInvoiceLines" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestPostInvoiceLinesWithItemVariant" - }, - { - "codeunitId": 139738, - "codeunitName": "APIV1 - Purchase Inv Lines E2E", - "method": "TestPostInvoiceLineWithSequence" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestAppliesToInvoiceNoAndIdSync" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestCreateCustomerPayment" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestCreateCustomerPaymentWithInvoiceId" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestCreateCustomerPaymentWithoutDocNo" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestCustomerAutofillDoesNotOverwrite" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestCustomerAutofillWhenGivingInvoiceNumber" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestCustomerNoAndIdSync" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestDeleteCustomerPayment" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestGetCustomerPayment" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestModifyCustomerPayment" - }, - { - "codeunitId": 139743, - "codeunitName": "APIV1 - Customer Payments E2E", - "method": "TestModifyCustomerPaymentWithRandomDocNo" - }, - { - "codeunitId": 139744, - "codeunitName": "APIV1 - PDF Document E2E", - "method": "TestGetPDFPurchaseInvoice" - }, - { - "codeunitId": 139744, - "codeunitName": "APIV1 - PDF Document E2E", - "method": "TestGetPDFSalesCreditMemo" - }, - { - "codeunitId": 139744, - "codeunitName": "APIV1 - PDF Document E2E", - "method": "TestGetPDFSalesInvoice" - }, - { - "codeunitId": 139744, - "codeunitName": "APIV1 - PDF Document E2E", - "method": "TestGetPDFSalesQuote" - }, - { - "codeunitId": 139745, - "codeunitName": "APIV1 - Journal Lines E2E", - "method": "TestCreateJournalLineWithDimensionsOnAccountWithDimensionSetup" - }, - { - "codeunitId": 139745, - "codeunitName": "APIV1 - Journal Lines E2E", - "method": "TestCreateJournalLineWithDisabledCopyVATSetup" - }, - { - "codeunitId": 139745, - "codeunitName": "APIV1 - Journal Lines E2E", - "method": "TestCreateJournalLineWithoutDimensionsOnAccountWithDimensionSetup" - }, - { - "codeunitId": 139745, - "codeunitName": "APIV1 - Journal Lines E2E", - "method": "TestCreateJournalLineWithOverridenDefaultDimension" + "codeunitId": 139709, + "codeunitName": "Sales Invoices E2E", + "method": "TestGetInvoicesAppliesDiscountPct" } ] diff --git a/src/DisabledTests/_Exclude_APIV2__Tests/_Exclude_APIV2__Tests.DisabledTest.json b/src/DisabledTests/_Exclude_APIV2__Tests/_Exclude_APIV2__Tests.DisabledTest.json index 2a73423912e..588bb59f3fd 100644 --- a/src/DisabledTests/_Exclude_APIV2__Tests/_Exclude_APIV2__Tests.DisabledTest.json +++ b/src/DisabledTests/_Exclude_APIV2__Tests/_Exclude_APIV2__Tests.DisabledTest.json @@ -1,184 +1,9 @@ [ - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestCreateItemWithCategoryCode" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestCreateItemWithCategoryId" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestCreateItemWithTemplate" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestCreateItemWithTemplateIgnoresFieldsSet" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestCreateItemWithUoMCode" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestCreateItemWithUoMId" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestCreateSimpleItem" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestDeleteItem" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestGetItemWithCategory" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestGetRelatedEntities" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestGetSimpleItem" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestModifyItem" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestModifyItemInventory" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestPatchItemWithCategoryCode" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestPatchItemWithCategoryId" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestPatchItemWithGenProdPostingGroup" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestPatchItemWithInventoryPostingGroup" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestUnassignGenProdPostingGroup" - }, - { - "codeunitId": 139800, - "codeunitName": "APIV2 - Items E2E", - "method": "TestUnassignInventoryPostingGroup" - }, - { - "codeunitId": 139801, - "codeunitName": "APIV2 - Accounts E2E", - "method": "TestGetAccounts" - }, - { - "codeunitId": 139804, - "codeunitName": "APIV2 - Payment Terms E2E", - "method": "TestGetPaymentTerms" - }, - { - "codeunitId": 139805, - "codeunitName": "APIV2 - Shipment Methods E2E", - "method": "TestGetShipmentMethods" - }, - { - "codeunitId": 139806, - "codeunitName": "APIV2 - Company Info. E2E", - "method": "TestGetCompanyInformation" - }, { "codeunitId": 139806, "codeunitName": "APIV2 - Company Info. E2E", "method": "TestGetCompanyAndEnvironmentDescriptions" }, - { - "codeunitId": 139806, - "codeunitName": "APIV2 - Company Info. E2E", - "method": "TestModifyCompanyInformation" - }, - { - "codeunitId": 139806, - "codeunitName": "APIV2 - Company Info. E2E", - "method": "TestModifyInvalidExperinceTier" - }, - { - "codeunitId": 139806, - "codeunitName": "APIV2 - Company Info. E2E", - "method": "TestModifyValidExperinceTier" - }, - { - "codeunitId": 139807, - "codeunitName": "APIV2 - Item Categories E2E", - "method": "TestCreateItemCategory" - }, - { - "codeunitId": 139807, - "codeunitName": "APIV2 - Item Categories E2E", - "method": "TestDeleteItemCategory" - }, - { - "codeunitId": 139807, - "codeunitName": "APIV2 - Item Categories E2E", - "method": "TestGetItemCategories" - }, - { - "codeunitId": 139807, - "codeunitName": "APIV2 - Item Categories E2E", - "method": "TestModifyItemCategory" - }, - { - "codeunitId": 139808, - "codeunitName": "APIV2 - Tax Groups E2E", - "method": "TestCreateTaxGroup" - }, - { - "codeunitId": 139808, - "codeunitName": "APIV2 - Tax Groups E2E", - "method": "TestDeleteTaxGroup" - }, - { - "codeunitId": 139808, - "codeunitName": "APIV2 - Tax Groups E2E", - "method": "TestGetTaxGroup" - }, - { - "codeunitId": 139808, - "codeunitName": "APIV2 - Tax Groups E2E", - "method": "TestGetTaxGroups" - }, - { - "codeunitId": 139808, - "codeunitName": "APIV2 - Tax Groups E2E", - "method": "TestModifyTaxGroup" - }, { "codeunitId": 139809, "codeunitName": "APIV2 - Sales Invoices E2E", @@ -189,3399 +14,144 @@ "codeunitName": "APIV2 - Sales Invoices E2E", "method": "TestActionCancelInvoice" }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestActionMakeCorrectiveCreditMemo" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestActionPostAndSendInvoice" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestActionPostInvoice" - }, { "codeunitId": 139809, "codeunitName": "APIV2 - Sales Invoices E2E", "method": "TestActionSendCancelledInvoice" }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestActionSendDraftInvoice" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestActionSendPostedInvoice" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestClearingManualDiscounts" - }, { "codeunitId": 139809, "codeunitName": "APIV2 - Sales Invoices E2E", "method": "TestCreateInvoiceThroughPageAndAPI" }, { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestDeleteInvoice" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestEmptyModifyInvoices" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestGetInvoiceFromPostedOrderCorrectOrderIdAndNo" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestGetInvoices" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestGetInvoicesAppliesDiscountPct" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestGetInvoicesRedistributesDiscountAmt" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestGetSalesInvoiceFromDraftId" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestModifyingWithBlankIdEmptiesTheCodeAndTheId" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestModifyInvoiceNumberForDraftInvoice" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestModifyInvoices" - }, - { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestModifyInvoiceSetManualDiscount" + "codeunitId": 139811, + "codeunitName": "APIV2 - Sales Orders E2E", + "method": "TestCreateOrderThroughPageAndAPI" }, { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestPartialModifyInvoices" + "codeunitId": 139823, + "codeunitName": "APIV2 - Sales Quotes E2E", + "method": "TestActionMakeOrderFromQuote" }, { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestPostInvoices" + "codeunitId": 139823, + "codeunitName": "APIV2 - Sales Quotes E2E", + "method": "TestCreateQuoteThroughPageAndAPI" }, { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestPostInvoiceWithCurrency" + "codeunitId": 139828, + "codeunitName": "APIV2 - Sales Credit Memos E2E", + "method": "TestActionCancelAndSendCorrectiveCreditMemo" }, { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestPostInvoiceWithDates" + "codeunitId": 139828, + "codeunitName": "APIV2 - Sales Credit Memos E2E", + "method": "TestActionCancelCorrectiveCreditMemo" }, { - "codeunitId": 139809, - "codeunitName": "APIV2 - Sales Invoices E2E", - "method": "TestPostInvoiceWithEmail" + "codeunitId": 139828, + "codeunitName": "APIV2 - Sales Credit Memos E2E", + "method": "TestCreateCreditMemoThroughPageAndAPI" }, { - "codeunitId": 139810, - "codeunitName": "APIV2 - Countries/Regions E2E", - "method": "TestCreateCountriesRegions" + "codeunitId": 139834, + "codeunitName": "APIV2 - Sales Inv. Lines E2E", + "method": "TestGettingLinesWithDifferentTypes" }, { - "codeunitId": 139810, - "codeunitName": "APIV2 - Countries/Regions E2E", - "method": "TestDeleteCountriesRegions" + "codeunitId": 139834, + "codeunitName": "APIV2 - Sales Inv. Lines E2E", + "method": "TestPatchingTheIdToItemChangesLineType" }, { - "codeunitId": 139810, - "codeunitName": "APIV2 - Countries/Regions E2E", - "method": "TestGetCountriesRegions" + "codeunitId": 139835, + "codeunitName": "APIV2 - Sales Order Lines E2E", + "method": "TestGettingLinesWithDifferentTypes" }, { - "codeunitId": 139810, - "codeunitName": "APIV2 - Countries/Regions E2E", - "method": "TestModifyCountriesRegions" + "codeunitId": 139835, + "codeunitName": "APIV2 - Sales Order Lines E2E", + "method": "TestPatchingTheIdToItemChangesLineType" }, { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestActionShipAndInvoice" + "codeunitId": 139839, + "codeunitName": "APIV2 - Item Variants E2E", + "method": "TestDeleteInUse" }, { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestClearingManualDiscounts" + "codeunitId": 139843, + "codeunitName": "APIV2 - Vendor Payments E2E", + "method": "TestCreateVendorPaymentWithoutDocNo" }, { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", + "codeunitId": 139851, + "codeunitName": "APIV2 - Purchase Orders E2E", "method": "TestCreateOrderThroughPageAndAPI" }, { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestDeleteOrders" - }, - { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestEmptyModifyOrders" - }, - { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestGetOrders" - }, - { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestGetOrdersAppliesDiscountPct" - }, - { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestGetOrdersRedistributesDiscountAmt" - }, - { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestModifyOrders" - }, - { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestModifyOrderSetManualDiscount" - }, - { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestPartialModifyOrders" - }, - { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestPostOrderForCustomerWithLocationCode" + "codeunitId": 139852, + "codeunitName": "APIV2 - Purch. Order Lines E2E", + "method": "TestGettingLinesWithDifferentTypes" }, { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestPostOrders" + "codeunitId": 139852, + "codeunitName": "APIV2 - Purch. Order Lines E2E", + "method": "TestPatchingTheIdToItemChangesLineType" }, { - "codeunitId": 139811, - "codeunitName": "APIV2 - Sales Orders E2E", - "method": "TestPostOrderWithCurrency" + "codeunitId": 139865, + "codeunitName": "APIV2 - Purch. Cr. Memos E2E", + "method": "TestCreateCreditMemoThroughPageAndAPI" }, { - "codeunitId": 139812, - "codeunitName": "APIV2 - UofM E2E", - "method": "TestDeleteUnitOfMeasure" + "codeunitId": 139867, + "codeunitName": "APIV2 - Apply Vendor Ent. E2E", + "method": "TestApplyVendorEntryAppliesPayment" }, { - "codeunitId": 139812, - "codeunitName": "APIV2 - UofM E2E", - "method": "TestGetUnitOfMeasure" + "codeunitId": 139928, + "codeunitName": "APIV2 - Purch. Ret. Shpts. E2E", + "method": "*" }, { - "codeunitId": 139812, - "codeunitName": "APIV2 - UofM E2E", - "method": "TestInsertUnitOfMeasure" + "codeunitId": 139908, + "codeunitName": "APIV2 - Bl. Purch. Orders E2E", + "method": "*" }, { - "codeunitId": 139812, - "codeunitName": "APIV2 - UofM E2E", - "method": "TestModifyUnitOfMeasure" + "codeunitId": 139927, + "codeunitName": "APIV2 - Sales Ord. Arch. E2E", + "method": "*" }, { - "codeunitId": 139813, - "codeunitName": "APIV2 - Currencies E2E", - "method": "TestCreateCurrency" + "codeunitId": 139909, + "codeunitName": "APIV2 - Bl. Sales Orders E2E", + "method": "*" }, { - "codeunitId": 139813, - "codeunitName": "APIV2 - Currencies E2E", - "method": "TestDeleteCurrency" + "codeunitId": 139924, + "codeunitName": "APIV2 - Sales Ret. Orders E2E", + "method": "*" }, { - "codeunitId": 139813, - "codeunitName": "APIV2 - Currencies E2E", - "method": "TestGetCurrencies" + "codeunitId": 139923, + "codeunitName": "APIV2 - Purch. Ret. Orders E2E", + "method": "*" }, { - "codeunitId": 139813, - "codeunitName": "APIV2 - Currencies E2E", - "method": "TestModifyCurrency" + "codeunitId": 139922, + "codeunitName": "APIV2 - Purch. Quotes E2E", + "method": "*" }, { - "codeunitId": 139814, - "codeunitName": "APIV2 - Payment Methods E2E", - "method": "TestCreatePaymentMethods" - }, - { - "codeunitId": 139814, - "codeunitName": "APIV2 - Payment Methods E2E", - "method": "TestDeletePaymentMethods" - }, - { - "codeunitId": 139814, - "codeunitName": "APIV2 - Payment Methods E2E", - "method": "TestGetPaymentMethods" - }, - { - "codeunitId": 139814, - "codeunitName": "APIV2 - Payment Methods E2E", - "method": "TestModifyPaymentMethods" - }, - { - "codeunitId": 139815, - "codeunitName": "APIV2 - Balance Sheet E2E", - "method": "TestGetBalanceSheetRecords" - }, - { - "codeunitId": 139816, - "codeunitName": "APIV2 - Income Statement E2E", - "method": "TestGetIncomeStatementRecords" - }, - { - "codeunitId": 139817, - "codeunitName": "APIV2 - CashFlow Statement E2E", - "method": "TestGetCashFlowRecords" - }, - { - "codeunitId": 139818, - "codeunitName": "APIV2 - Trial Balance E2E", - "method": "TestGetTrialBalanceRecords" - }, - { - "codeunitId": 139819, - "codeunitName": "APIV2 - Aged AP E2E", - "method": "TestGetAgedAPRecords" - }, - { - "codeunitId": 139820, - "codeunitName": "APIV2 - Aged AR E2E", - "method": "TestGetAgedARRecords" - }, - { - "codeunitId": 139821, - "codeunitName": "APIV2 - Ret. Earnings E2E", - "method": "TestRetainedEarningsStatementRecords" - }, - { - "codeunitId": 139822, - "codeunitName": "APIV2 - Employees E2E", - "method": "TestCreateEmployee" - }, - { - "codeunitId": 139822, - "codeunitName": "APIV2 - Employees E2E", - "method": "TestDeleteEmployee" - }, - { - "codeunitId": 139822, - "codeunitName": "APIV2 - Employees E2E", - "method": "TestGetEmployee" - }, - { - "codeunitId": 139822, - "codeunitName": "APIV2 - Employees E2E", - "method": "TestModifyEmployee" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestActionMakeInvoiceFromQuote" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestActionMakeOrderFromQuote" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestActionSendQuote" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestClearingManualDiscounts" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestCreateQuoteThroughPageAndAPI" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestDeleteQuotes" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestEmptyModifyQuotes" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestGetQuotes" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestGetQuotesAppliesDiscountPct" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestGetQuotesRedistributesDiscountAmt" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestModifyQuotes" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestModifyQuoteSetManualDiscount" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestPartialModifyQuotes" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestPostQuotes" - }, - { - "codeunitId": 139823, - "codeunitName": "APIV2 - Sales Quotes E2E", - "method": "TestPostQuoteWithCurrency" - }, - { - "codeunitId": 139824, - "codeunitName": "APIV2 - Dimensions E2E", - "method": "TestGetDimensions" - }, - { - "codeunitId": 139824, - "codeunitName": "APIV2 - Dimensions E2E", - "method": "TestGetDimensionValues" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreateDoesntWorkWithAlreadyExistingCode" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreateJournalLineDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreatePurchaseCrMemoDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreatePurchaseInvoiceDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreatePurchaseOrderDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreateSalesCrMemoDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreateSalesInvoiceDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreateSalesOrderDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreateSalesQuoteDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestCreateTimeRegEntryDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestDeleteDimensionSetLineOfGenJournalLines" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestDeletePurchaseCrMemoDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestDeletePurchaseInvoiceDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestDeletePurchaseOrderDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestDeleteSalesCrMemoDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestDeleteSalesInvoiceDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestDeleteSalesOrderDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestDeleteSalesQuoteDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestDeleteTimeRegEntryDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfGLEntry" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfJournalLines" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfPurchaseCrMemo" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfPurchaseInvoice" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfPurchaseOrder" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfSalesCrMemo" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfSalesInvoice" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfSalesOrder" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfSalesQuote" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestGetDimensionSetLinesOfTimeRegEntry" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifyDimensionSetLineOfGenJournalLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifyDimensionSetLineOfSalesOrder" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifyDimensionSetLineOfSalesQuote" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifyOfDimensionCodeDoesntWork" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifyPurchaseCrMemoDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifyPurchaseInvoiceDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifyPurchaseOrderDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifySalesCrMemoDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifySalesInvoiceDimensionSetLine" - }, - { - "codeunitId": 139825, - "codeunitName": "APIV2 - Dim. Set Lines E2E", - "method": "TestModifyTimeRegEntryDimensionSetLine" - }, - { - "codeunitId": 139827, - "codeunitName": "APIV2 - Journals E2E", - "method": "TestActionPostGenJournalBatch" - }, - { - "codeunitId": 139827, - "codeunitName": "APIV2 - Journals E2E", - "method": "TestCreateJournal" - }, - { - "codeunitId": 139827, - "codeunitName": "APIV2 - Journals E2E", - "method": "TestDeleteJournal" - }, - { - "codeunitId": 139827, - "codeunitName": "APIV2 - Journals E2E", - "method": "TestGetJournals" - }, - { - "codeunitId": 139827, - "codeunitName": "APIV2 - Journals E2E", - "method": "TestModifyJournal" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestActionCancelAndSendCorrectiveCreditMemo" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestActionCancelCorrectiveCreditMemo" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestActionPostAndSendCreditMemo" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestActionPostCreditMemo" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestActionSendCancelledCreditMemo" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestActionSendPostedCreditMemo" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestClearingManualDiscounts" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestCreateCreditMemoThroughPageAndAPI" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestDeleteCreditMemo" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestEmptyModifyCreditMemos" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestGetCreditMemos" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestGetCreditMemosAppliesDiscountPct" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestGetCreditMemosRedistributesDiscountAmt" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestModifyCreditMemos" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestModifyCreditMemoSetManualDiscount" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestPartialModifyCreditMemos" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestPostCreditMemos" - }, - { - "codeunitId": 139828, - "codeunitName": "APIV2 - Sales Credit Memos E2E", - "method": "TestPostCreditMemoWithCurrency" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestActionPostPurchaseInvoice" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestCreateInvoiceThroughPageAndAPI" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestDeleteInvoice" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestEmptyModifyInvoices" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestGetInvoiceFromPostedOrderCorrectOrderIdAndNo" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestGetInvoices" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestGetPurchaseInvoiceFromDraftId" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestModifyInvoices" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestPartialModifyInvoices" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestPostInvoices" - }, - { - "codeunitId": 139829, - "codeunitName": "APIV2 - Purchase Invoices E2E", - "method": "TestPostPurchaseInvoiceWithCurrency" - }, - { - "codeunitId": 139830, - "codeunitName": "APIV2 - GLEntries E2E", - "method": "TestGetGLEntries" - }, - { - "codeunitId": 139831, - "codeunitName": "APIV2 - Automation RS Package", - "method": "TestApplyRSPackage" - }, - { - "codeunitId": 139831, - "codeunitName": "APIV2 - Automation RS Package", - "method": "TestCreateRSPackage" - }, - { - "codeunitId": 139831, - "codeunitName": "APIV2 - Automation RS Package", - "method": "TestImportRSPackage" - }, - { - "codeunitId": 139831, - "codeunitName": "APIV2 - Automation RS Package", - "method": "TestImportWrongRSPackage" - }, - { - "codeunitId": 139831, - "codeunitName": "APIV2 - Automation RS Package", - "method": "TestUploadRSPackageFile" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreateDraftInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreateDraftOrderAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreateDraftPurchaseCreditMemoAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreateDraftPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreateDraftPurchaseOrderAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreateGLEntryAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreateJournalLineAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreatePostedInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreatePostedPurchaseCreditMemoAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreatePostedPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestCreateQuoteAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestDeleteDraftInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestDeleteDraftPurchaseCreditMemoAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestDeleteDraftPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestDeleteGLEntryAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestDeleteJournalLineAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestDeletePostedInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestDeletePostedPurchaseCreditMemoAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestDeletePostedPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestDeleteQuoteAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetDraftInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetDraftInvoiceAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetDraftOrderAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetDraftOrderAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetDraftPurchaseCreditMemoAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetDraftPurchaseInvoiceAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetDraftPurchaseOrderAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetGLEntryAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetGLEntryAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetJournalAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetJournalLineAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetJournalLineAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetPostedInvoiceAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetPostedInvoiceAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetPostedPurchaseCreditMemoAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetPostedPurchaseInvoiceAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetQuoteAttachment" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestGetQuoteAttachments" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestLinkedAttachmentContentChangeKeepsOtherFieldsUnchanged" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestLinkedAttachmentDocumentIdChangeNotAllowed" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestLinkedAttachmentFileNameChangeKeepsOtherFieldsUnchanged" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestTransferAttachmentFromDraftToPostedInvoice" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestTransferAttachmentFromDraftToPostedPurchaseCreditMemo" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestTransferAttachmentFromDraftToPostedPurchaseInvoice" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestUpdateGenJournalLineAttachmentBinaryContent" - }, - { - "codeunitId": 139833, - "codeunitName": "APIV2 - Attachments E2E", - "method": "TestUpdateGLEntryAttachmentBinaryContent" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestDeleteInvoiceLine" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestDeletingLineKeepsInvoiceDiscountAmt" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestDeletingLineMovesInvoiceDiscountPct" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestDeletingLineRemovesInvoiceDiscountPct" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestGetInvoiceLineDirectly" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestGetInvoiceLines" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestGetInvoiceLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestGetPostedInvoiceLines" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestGettingLinesWithDifferentTypes" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestInsertingLineKeepsInvoiceDiscountAmt" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestInsertingLineUpdatesInvoiceDiscountPct" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestModifyingLineKeepsInvoiceDiscountAmt" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestModifyingLineUpdatesInvoiceDiscountPct" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestModifyInvoiceLine" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestModifyInvoiceLineWithUoM" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestPatchingTheIdToAccountChangesLineType" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestPatchingTheIdToItemChangesLineType" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestPostingBlankLineDefaultsToCommentType" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestPostInvoiceLines" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestPostInvoiceLinesWithItemVariant" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestPostInvoiceLinesWithUoM" - }, - { - "codeunitId": 139834, - "codeunitName": "APIV2 - Sales Inv. Lines E2E", - "method": "TestPostInvoiceLineWithSequence" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestCreatingOrderLineWithAssemblyBOM" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestDeleteOrderLine" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestDeletingLineKeepsOrderDiscountAmt" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestDeletingLineMovesOrderDiscountPct" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestDeletingLineRemovesOrderDiscountPct" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestExpandReturnsCorrectDocumentLines" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestExpandReturnsCorrectDocumentLinesWithMultipleDocuments" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestGetOrderLineDirectly" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestGetOrderLines" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestGetOrderLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestGettingLinesWithDifferentTypes" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestInsertingLineKeepsOrderDiscountAmt" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestInsertingLineUpdatesOrderDiscountPct" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestModifyingLineKeepsOrderDiscountAmt" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestModifyingLineUpdatesOrderDiscountPct" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestModifyOrderLines" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestPatchingTheIdToAccountChangesLineType" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestPatchingTheIdToItemChangesLineType" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestPostingBlankLineDefaultsToCommentType" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestPostOrderLines" - }, - { - "codeunitId": 139835, - "codeunitName": "APIV2 - Sales Order Lines E2E", - "method": "TestPostOrderLineWithItemVariant" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestDeleteQuoteLine" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestDeletingLineKeepsQuoteDiscountAmt" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestDeletingLineMovesQuoteDiscountPct" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestDeletingLineRemovesQuoteDiscountPct" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestGetQuoteLineDirectly" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestGetQuoteLines" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestGetQuoteLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestInsertingLineKeepsQuoteDiscountAmt" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestInsertingLineUpdatesQuoteDiscountPct" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestModifyingLineKeepsQuoteDiscountAmt" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestModifyingLineUpdatesQuoteDiscountPct" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestModifyQuoteLines" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestPostingBlankLineDefaultsToCommentType" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestPostQuoteLines" - }, - { - "codeunitId": 139836, - "codeunitName": "APIV2 - Sales Quote Lines E2E", - "method": "TestPostQuoteLinesWithItemVariant" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestDeleteCreditMemoLine" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestDeletePostedCreditMemoLine" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestDeletingLineKeepsCreditMemoDiscountAmt" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestDeletingLineMovesCreditMemoDiscountPct" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestDeletingLineRemovesCreditMemoDiscountPct" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestGetCreditMemoLineDirectly" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestGetCreditMemoLines" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestGetCreditMemoLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestGetPostedCreditMemoLines" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestGettingLinesWithDifferentTypes" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestInsertingLineKeepsCreditMemoDiscountAmt" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestInsertingLineUpdatesCreditMemoDiscountPct" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestModifyCreditMemoLines" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestModifyingLineKeepsCreditMemoDiscountAmt" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestModifyingLineUpdatesCreditMemoDiscountPct" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestPatchingTheIdToAccountChangesLineType" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestPatchingTheIdToItemChangesLineType" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestPostCreditMemoLines" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestPostCreditMemoLinesWithItemVariant" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestPostCreditMemoLineWithSequence" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestPostingBlankLineDefaultsToCommentType" - }, - { - "codeunitId": 139837, - "codeunitName": "APIV2 - Sales CrMemo Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestDeleteInvoiceLine" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestDeletingLineRemovesInvoiceDiscountPct" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestGetInvoiceLineDirectly" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestGetInvoiceLines" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestGetInvoiceLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestGetPostedInvoiceLines" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestInsertingLineKeepsInvoiceDiscountAmt" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestInsertingLineUpdatesInvoiceDiscountPct" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestModifyingLineUpdatesInvoiceDiscountPct" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestModifyInvoiceLines" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestPostingBlankLineDefaultsToCommentType" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestPostInvoiceLines" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestPostInvoiceLinesWithItemVariant" - }, - { - "codeunitId": 139838, - "codeunitName": "APIV2 - Purchase Inv Lines E2E", - "method": "TestPostInvoiceLineWithSequence" - }, - { - "codeunitId": 139839, - "codeunitName": "APIV2 - Item Variants E2E", - "method": "TestCreateItemVariantWithItemId" - }, - { - "codeunitId": 139839, - "codeunitName": "APIV2 - Item Variants E2E", - "method": "TestCreateItemVariantWithItemNumber" - }, - { - "codeunitId": 139839, - "codeunitName": "APIV2 - Item Variants E2E", - "method": "TestCreateItemVariantWithItemNumberAndItemId" - }, - { - "codeunitId": 139839, - "codeunitName": "APIV2 - Item Variants E2E", - "method": "TestDeleteInUse" - }, - { - "codeunitId": 139839, - "codeunitName": "APIV2 - Item Variants E2E", - "method": "TestDeleteItemVariant" - }, - { - "codeunitId": 139839, - "codeunitName": "APIV2 - Item Variants E2E", - "method": "TestGetItemVariant" - }, - { - "codeunitId": 139839, - "codeunitName": "APIV2 - Item Variants E2E", - "method": "TestModifyItemVariant" - }, - { - "codeunitId": 139839, - "codeunitName": "APIV2 - Item Variants E2E", - "method": "TestModifyItemVariantItemId" - }, - { - "codeunitId": 139839, - "codeunitName": "APIV2 - Item Variants E2E", - "method": "TestModifyItemVariantItemNumber" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestAppliesToInvoiceNoAndIdSync" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestCreateCustomerPayment" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestCreateCustomerPaymentWithInvoiceId" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestCreateCustomerPaymentWithoutDocNo" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestCustomerAutofillDoesNotOverwrite" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestCustomerAutofillWhenGivingInvoiceNumber" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestCustomerNoAndIdSync" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestDeleteCustomerPayment" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestGetCustomerPayment" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestModifyCustomerPayment" - }, - { - "codeunitId": 139840, - "codeunitName": "APIV2 - Customer Payments E2E", - "method": "TestModifyCustomerPaymentWithRandomDocNo" - }, - { - "codeunitId": 139841, - "codeunitName": "APIV2 - PDF Document E2E", - "method": "TestGetPDFPurchaseCreditMemo" - }, - { - "codeunitId": 139841, - "codeunitName": "APIV2 - PDF Document E2E", - "method": "TestGetPDFPurchaseInvoice" - }, - { - "codeunitId": 139841, - "codeunitName": "APIV2 - PDF Document E2E", - "method": "TestGetPDFSalesCreditMemo" - }, - { - "codeunitId": 139841, - "codeunitName": "APIV2 - PDF Document E2E", - "method": "TestGetPDFSalesInvoice" - }, - { - "codeunitId": 139841, - "codeunitName": "APIV2 - PDF Document E2E", - "method": "TestGetPDFSalesOrder" - }, - { - "codeunitId": 139841, - "codeunitName": "APIV2 - PDF Document E2E", - "method": "TestGetPDFSalesQuote" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadataContact" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadataContactWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadataCustomer" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadataCustomerWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadataEmployee" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadataEmployeeWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadataItem" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadataVendor" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadataVendorWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureMetadatItemWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueContact" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueContactWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueCustomer" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueCustomerWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueEmployee" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueEmployeeWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueItem" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueItemWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueVendor" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestGetPictureValueVendorWithoutPicture" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureDeleteContact" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureDeleteCustomer" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureDeleteEmployee" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureDeleteItem" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureDeleteVendor" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureReplaceContact" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureReplaceCustomer" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureReplaceEmployee" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureReplaceItem" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureReplaceVendor" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureUploadContact" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureUploadCustomer" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureUploadEmployee" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureUploadItem" - }, - { - "codeunitId": 139842, - "codeunitName": "APIV2 - Pictures E2E", - "method": "TestPictureUploadVendor" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestAppliesToInvoiceNoAndIdSync" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestAppliesToInvoiceNumberEmptyForNonInvoiceApplication" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestCreateVendorPayment" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestCreateVendorPaymentWithInvoiceId" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestCreateVendorPaymentWithoutDocNo" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestDeleteVendorPayment" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestGetVendorPayment" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestGetVendorPaymentWithoutInvoiceApplicationIsVisible" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestModifyVendorPayment" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestModifyVendorPaymentWithRandomDocNo" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestVendorAutofillDoesNotOverwrite" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestVendorAutofillWhenGivingInvoiceNumber" - }, - { - "codeunitId": 139843, - "codeunitName": "APIV2 - Vendor Payments E2E", - "method": "TestVendorNoAndIdSync" - }, - { - "codeunitId": 139847, - "codeunitName": "APIV2 - Sales Shipments E2E", - "method": "TestExpandDimensions" - }, - { - "codeunitId": 139847, - "codeunitName": "APIV2 - Sales Shipments E2E", - "method": "TestGetSalesShipments" - }, - { - "codeunitId": 139848, - "codeunitName": "APIV2 - Sales Ship. Lines E2E", - "method": "TestExpandDimensions" - }, - { - "codeunitId": 139848, - "codeunitName": "APIV2 - Sales Ship. Lines E2E", - "method": "TestGetLineDirectly" - }, - { - "codeunitId": 139848, - "codeunitName": "APIV2 - Sales Ship. Lines E2E", - "method": "TestGetShipmentLines" - }, - { - "codeunitId": 139848, - "codeunitName": "APIV2 - Sales Ship. Lines E2E", - "method": "TestGetShipmentLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139849, - "codeunitName": "APIV2 - Purchase Receipts E2E", - "method": "TestExpandDimensions" - }, - { - "codeunitId": 139849, - "codeunitName": "APIV2 - Purchase Receipts E2E", - "method": "TestGetPurchaseReceipts" - }, - { - "codeunitId": 139850, - "codeunitName": "APIV2 - Purch. Rcpt. Lines E2E", - "method": "TestExpandDimensions" - }, - { - "codeunitId": 139850, - "codeunitName": "APIV2 - Purch. Rcpt. Lines E2E", - "method": "TestGetLineDirectly" - }, - { - "codeunitId": 139850, - "codeunitName": "APIV2 - Purch. Rcpt. Lines E2E", - "method": "TestGetReceiptLines" - }, - { - "codeunitId": 139850, - "codeunitName": "APIV2 - Purch. Rcpt. Lines E2E", - "method": "TestGetReceiptLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestActionRecieveAndInvoice" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestClearingManualDiscounts" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestCreateOrderThroughPageAndAPI" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestDeleteOrders" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestEmptyModifyOrders" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestGetOrders" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestGetOrdersAppliesDiscountPct" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestGetOrdersRedistributesDiscountAmt" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestModifyOrders" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestModifyOrderSetManualDiscount" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestPartialModifyOrders" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestPostOrderForCustomerWithLocationCode" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestPostOrders" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestPostOrdersWithEmptyShippingAddress" - }, - { - "codeunitId": 139851, - "codeunitName": "APIV2 - Purchase Orders E2E", - "method": "TestPostOrderWithCurrency" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestDeleteOrderLine" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestDeletingLineKeepsOrderDiscountAmt" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestDeletingLineMovesOrderDiscountPct" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestDeletingLineRemovesOrderDiscountPct" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestGetOrderLineDirectly" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestGetOrderLines" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestGetOrderLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestGettingLinesWithDifferentTypes" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestInsertingLineKeepsOrderDiscountAmt" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestInsertingLineUpdatesOrderDiscountPct" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestModifyingLineKeepsOrderDiscountAmt" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestModifyingLineUpdatesOrderDiscountPct" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestModifyOrderLines" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestPatchingTheIdToAccountChangesLineType" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestPatchingTheIdToItemChangesLineType" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestPostingBlankLineDefaultsToCommentType" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestPostOrderLines" - }, - { - "codeunitId": 139852, - "codeunitName": "APIV2 - Purch. Order Lines E2E", - "method": "TestPostOrderLineWithItemVariant" - }, - { - "codeunitId": 139853, - "codeunitName": "APIV2 - Contacts Inf. E2E", - "method": "TestGetCustomerContactInformation" - }, - { - "codeunitId": 139853, - "codeunitName": "APIV2 - Contacts Inf. E2E", - "method": "TestGetCustomerContactsInformation" - }, - { - "codeunitId": 139853, - "codeunitName": "APIV2 - Contacts Inf. E2E", - "method": "TestGetVendorContactInformation" - }, - { - "codeunitId": 139853, - "codeunitName": "APIV2 - Contacts Inf. E2E", - "method": "TestGetVendorContactsInformation" - }, - { - "codeunitId": 139854, - "codeunitName": "APIV2 - Item Ledg. Entries E2E", - "method": "TestGetItemLedgerEntries" - }, - { - "codeunitId": 139855, - "codeunitName": "APIV2 - Opportunities E2E", - "method": "TestCannotPatchContactNoOfWonOpportunity" - }, - { - "codeunitId": 139855, - "codeunitName": "APIV2 - Opportunities E2E", - "method": "TestCannotPatchSPCodeOfWonOpportunity" - }, - { - "codeunitId": 139855, - "codeunitName": "APIV2 - Opportunities E2E", - "method": "TestCreateOpportunity" - }, - { - "codeunitId": 139855, - "codeunitName": "APIV2 - Opportunities E2E", - "method": "TestCreateOpportunityContactNo" - }, - { - "codeunitId": 139855, - "codeunitName": "APIV2 - Opportunities E2E", - "method": "TestGetOpportunities" - }, - { - "codeunitId": 139855, - "codeunitName": "APIV2 - Opportunities E2E", - "method": "TestPatchOpportunity" - }, - { - "codeunitId": 139856, - "codeunitName": "APIV2 - GenProdPostGroup E2E", - "method": "TestGetGenProdPostGroups" - }, - { - "codeunitId": 139857, - "codeunitName": "APIV2 - InventoryPostGroup E2E", - "method": "TestGetInventoryPostGroups" - }, - { - "codeunitId": 139858, - "codeunitName": "APIV2 Currency Exch. Rate E2E", - "method": "TestGetCurrencyExchangeRates" - }, - { - "codeunitId": 139858, - "codeunitName": "APIV2 Currency Exch. Rate E2E", - "method": "TestSingleGetCurrencyExchangeRate" - }, - { - "codeunitId": 139859, - "codeunitName": "APIV2 - Accounting Periods E2E", - "method": "TestGetAccountingPeriods" - }, - { - "codeunitId": 139860, - "codeunitName": "APIV2 - G/L Setup E2E", - "method": "TestGetGLSetup" - }, - { - "codeunitId": 139861, - "codeunitName": "APIV2JobQueueLogEntriesE2E", - "method": "TestGetJobQueueLogEntry" - }, - { - "codeunitId": 139862, - "codeunitName": "APIV2JobQueueEntriesE2E", - "method": "TestGetCorrespondingJobQueueLogEntryFromExpand" - }, - { - "codeunitId": 139862, - "codeunitName": "APIV2JobQueueEntriesE2E", - "method": "TestGetCorrespondingJobQueueLogEntryFromSubPage" - }, - { - "codeunitId": 139862, - "codeunitName": "APIV2JobQueueEntriesE2E", - "method": "TestGetJobQueueEntry" - }, - { - "codeunitId": 139862, - "codeunitName": "APIV2JobQueueEntriesE2E", - "method": "TestRescheduleJobQueueEntry" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestActionCancelCorrectiveCreditMemo" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestActionPostCreditMemo" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestClearingManualDiscounts" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestCreateCreditMemoThroughPageAndAPI" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestDeleteCreditMemo" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestEmptyModifyCreditMemos" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestGetCreditMemos" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestModifyCreditMemos" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestModifyCreditMemoSetManualDiscount" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestPartialModifyCreditMemos" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestPostCreditMemos" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestPostCreditMemoWithCurrency" - }, - { - "codeunitId": 139865, - "codeunitName": "APIV2 - Purch. Cr. Memos E2E", - "method": "TestPostCreditMemoWithVendorCreditMemoNo" - }, - { - "codeunitId": 139866, - "codeunitName": "APIV2 - Contacts E2E", - "method": "TestDeleteContact" - }, - { - "codeunitId": 139866, - "codeunitName": "APIV2 - Contacts E2E", - "method": "TestGetContactWithAddressAndSpecialCharacters" - }, - { - "codeunitId": 139866, - "codeunitName": "APIV2 - Contacts E2E", - "method": "TestGetSimpleContact" - }, - { - "codeunitId": 139866, - "codeunitName": "APIV2 - Contacts E2E", - "method": "TestModifyContactWithAddress" - }, - { - "codeunitId": 139867, - "codeunitName": "APIV2 - Apply Vendor Ent. E2E", - "method": "TestApplyVendorEntryAppliesPayment" - }, - { - "codeunitId": 139867, - "codeunitName": "APIV2 - Apply Vendor Ent. E2E", - "method": "TestGetApplyVendorEntriesFailsWhenNoVendor" - }, - { - "codeunitId": 139867, - "codeunitName": "APIV2 - Apply Vendor Ent. E2E", - "method": "TestGetApplyVendorEntriesReturnsOpenEntries" - }, - { - "codeunitId": 139868, - "codeunitName": "APIV2 - Locations E2E", - "method": "TestCreateLocation" - }, - { - "codeunitId": 139868, - "codeunitName": "APIV2 - Locations E2E", - "method": "TestCreateSalesOrderLineWithLocation" - }, - { - "codeunitId": 139868, - "codeunitName": "APIV2 - Locations E2E", - "method": "TestDeleteLocation" - }, - { - "codeunitId": 139868, - "codeunitName": "APIV2 - Locations E2E", - "method": "TestGetLocation" - }, - { - "codeunitId": 139868, - "codeunitName": "APIV2 - Locations E2E", - "method": "TestModifyLocationWithAddress" - }, - { - "codeunitId": 139869, - "codeunitName": "APIV2 - Cust. Ret. Reasons E2E", - "method": "TestCreateReasonCode" - }, - { - "codeunitId": 139869, - "codeunitName": "APIV2 - Cust. Ret. Reasons E2E", - "method": "TestDeleteReasonCode" - }, - { - "codeunitId": 139869, - "codeunitName": "APIV2 - Cust. Ret. Reasons E2E", - "method": "TestGetReasonCode" - }, - { - "codeunitId": 139869, - "codeunitName": "APIV2 - Cust. Ret. Reasons E2E", - "method": "TestModifyReasonCode" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestCreateLineThroughPageAndAPI" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestDeleteCreditMemoLine" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestDeletePostedCreditMemoLine" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestGetCreditMemoLineDirectly" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestGetCreditMemoLines" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestGetCreditMemoLinesDirectlyWithDocumentIdFilter" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestGetPostedCreditMemoLines" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestGettingLinesWithDifferentTypes" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestModifyCreditMemoLines" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestPatchingTheIdToAccountChangesLineType" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestPatchingTheIdToItemChangesLineType" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestPatchingTheTypeBlanksIds" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestPostCreditMemoLines" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestPostCreditMemoLinesWithItemVariant" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestPostCreditMemoLineWithSequence" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestPostingBlankLineDefaultsToCommentType" - }, - { - "codeunitId": 139874, - "codeunitName": "APIV2 - Purch. Cr.M. Lines E2E", - "method": "TestPostingCommentLine" - }, - { - "codeunitId": 139882, - "codeunitName": "APIV2 - Salesperson/Purch E2E", - "method": "CreateSalespersonPurchaser" - }, - { - "codeunitId": 139882, - "codeunitName": "APIV2 - Salesperson/Purch E2E", - "method": "DeleteSalespersonPurchaser" - }, - { - "codeunitId": 139882, - "codeunitName": "APIV2 - Salesperson/Purch E2E", - "method": "GetSalespersonPurchaser" - }, - { - "codeunitId": 139882, - "codeunitName": "APIV2 - Salesperson/Purch E2E", - "method": "ModifySalespersonPurchaserJobTitle" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreateCustomerAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreateDraftInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreateDraftOrderAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreateDraftPurchaseCreditMemoAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreateDraftPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreateDraftPurchaseOrderAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreatePostedInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreatePostedPurchaseCreditMemoAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreatePostedPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreateQuoteAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestCreateVendorAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeleteDraftInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeleteDraftPurchaseCreditMemoAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeleteDraftPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeleteEmployeeAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeleteJobAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeletePostedInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeletePostedPurchaseCreditMemoAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeletePostedPurchaseInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeleteQuoteAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestDeleteVendorAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetCustomerAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetDraftInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetDraftInvoiceAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetDraftOrderAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetDraftPurchaseCreditMemoAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetDraftPurchaseInvoiceAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetDraftPurchaseOrderAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetEmployeeAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetItemAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetJobAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetPostedInvoiceAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetPostedInvoiceAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetPostedPurchaseCreditMemoAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetPostedPurchaseInvoiceAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetQuoteAttachment" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetQuoteAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestGetVendorAttachments" - }, - { - "codeunitId": 139899, - "codeunitName": "APIV2 - Document Attach. E2E", - "method": "TestUpdateCustomerAttachmentBinaryContent" - }, - { - "codeunitId": 139906, - "codeunitName": "APIV2 - FA Locations E2E", - "method": "TestCreateFALocation" - }, - { - "codeunitId": 139906, - "codeunitName": "APIV2 - FA Locations E2E", - "method": "TestDeleteFALocation" - }, - { - "codeunitId": 139906, - "codeunitName": "APIV2 - FA Locations E2E", - "method": "TestGetFALocation" - }, - { - "codeunitId": 139906, - "codeunitName": "APIV2 - FA Locations E2E", - "method": "TestModifyFALocation" - }, - { - "codeunitId": 139907, - "codeunitName": "APIV2 - Fixed Assets E2E", - "method": "TestCreateFixedAsset" - }, - { - "codeunitId": 139907, - "codeunitName": "APIV2 - Fixed Assets E2E", - "method": "TestDeleteFixedAsset" - }, - { - "codeunitId": 139907, - "codeunitName": "APIV2 - Fixed Assets E2E", - "method": "TestGetFixedAsset" - }, - { - "codeunitId": 139907, - "codeunitName": "APIV2 - Fixed Assets E2E", - "method": "TestModifyFixedAsset" - }, - { - "codeunitId": 139908, - "method": "TestGetBlanketPurchaseOrders", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestGetBlanketPurchaseOrderById", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestGetBlanketSalesOrders", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestGetBlanketSalesOrderById", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139917, - "method": "TestGetApprovalEntries", - "codeunitName": "APIV2 - Approval Entries E2E" - }, - { - "codeunitId": 139918, - "method": "TestGetApprovalUserSetup", - "codeunitName": "APIV2 - Approval UserSetup E2E" - }, - { - "codeunitId": 139919, - "method": "TestGetPostedApprovalEntries", - "codeunitName": "APIV2 PstdApprovalEntries E2E" - }, - { - "codeunitId": 139920, - "method": "TestGetApprovalEntries", - "codeunitName": "APIV2 - Workflow Approvers E2E" - }, - { - "codeunitId": 139921, - "method": "TestGetApprovalEntries", - "codeunitName": "APIV2 - Workflows E2E" - }, - { - "codeunitId": 139922, - "method": "TestGetPurchaseQuotes", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestGetPurchaseQuoteById", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139923, - "method": "TestGetPurchaseReturnOrders", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestGetPurchaseReturnOrderById", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestGetSalesReturnOrders", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestGetSalesReturnOrderById", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestGetAssemblyOrders", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestGetAssemblyOrderById", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestGetTransferOrders", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestGetTransferOrderById", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139927, - "method": "TestGetSalesOrderArchives", - "codeunitName": "APIV2 - Sales Ord. Arch. E2E" - }, - { - "codeunitId": 139927, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Sales Ord. Arch. E2E" - }, - { - "codeunitId": 139927, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Sales Ord. Arch. E2E" - }, - { - "codeunitId": 139927, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Sales Ord. Arch. E2E" - }, - { - "codeunitId": 139928, - "method": "TestGetPurchaseReturnShipments", - "codeunitName": "APIV2 - Purch. Ret. Shpts. E2E" - }, - { - "codeunitId": 139928, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Purch. Ret. Shpts. E2E" - }, - { - "codeunitId": 139928, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Purch. Ret. Shpts. E2E" - }, - { - "codeunitId": 139928, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Purch. Ret. Shpts. E2E" - }, - { - "codeunitId": 139908, - "method": "TestGetBlanketPurchaseOrders", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestGetBlanketPurchaseOrderById", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139908, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Bl. Purch. Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestGetBlanketSalesOrders", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestGetBlanketSalesOrderById", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139909, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Bl. Sales Orders E2E" - }, - { - "codeunitId": 139917, - "method": "TestGetApprovalEntries", - "codeunitName": "APIV2 - Approval Entries E2E" - }, - { - "codeunitId": 139918, - "method": "TestGetApprovalUserSetup", - "codeunitName": "APIV2 - Approval UserSetup E2E" - }, - { - "codeunitId": 139919, - "method": "TestGetPostedApprovalEntries", - "codeunitName": "APIV2 PstdApprovalEntries E2E" - }, - { - "codeunitId": 139920, - "method": "TestGetApprovalEntries", - "codeunitName": "APIV2 - Workflow Approvers E2E" - }, - { - "codeunitId": 139921, - "method": "TestGetApprovalEntries", - "codeunitName": "APIV2 - Workflows E2E" - }, - { - "codeunitId": 139922, - "method": "TestGetPurchaseQuotes", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestGetPurchaseQuoteById", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139922, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Purch. Quotes E2E" - }, - { - "codeunitId": 139923, - "method": "TestGetPurchaseReturnOrders", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestGetPurchaseReturnOrderById", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139923, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Purch. Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestGetSalesReturnOrders", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestGetSalesReturnOrderById", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139924, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Sales Ret. Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestGetAssemblyOrders", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestGetAssemblyOrderById", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139925, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Assembly Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestGetTransferOrders", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestGetTransferOrderById", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139926, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Transfer Orders E2E" + "codeunitId": 139925, + "codeunitName": "APIV2 - Assembly Orders E2E", + "method": "*" }, { "codeunitId": 139926, - "method": "TestExpandLines", - "codeunitName": "APIV2 - Transfer Orders E2E" - }, - { - "codeunitId": 139927, - "method": "TestGetSalesOrderArchives", - "codeunitName": "APIV2 - Sales Ord. Arch. E2E" - }, - { - "codeunitId": 139927, - "method": "TestExpandDimensionSetLines", - "codeunitName": "APIV2 - Sales Ord. Arch. E2E" - }, - { - "codeunitId": 139927, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Sales Ord. Arch. E2E" - }, - { - "codeunitId": 139927, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Sales Ord. Arch. E2E" - }, - { - "codeunitId": 139928, - "method": "TestGetPurchaseReturnShipments", - "codeunitName": "APIV2 - Purch. Ret. Shpts. E2E" - }, - { - "codeunitId": 139928, - "method": "TestExpandAttachments", - "codeunitName": "APIV2 - Purch. Ret. Shpts. E2E" - }, - { - "codeunitId": 139928, - "method": "TestExpandDocumentAttachments", - "codeunitName": "APIV2 - Purch. Ret. Shpts. E2E" - }, - { - "codeunitId": 139928, - "method": "TestExpandPdfDocument", - "codeunitName": "APIV2 - Purch. Ret. Shpts. E2E" + "codeunitName": "APIV2 - Transfer Orders E2E", + "method": "*" } ] diff --git a/src/Layers/APAC/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al b/src/Layers/APAC/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al index 707e6a229cd..0d44ad12a0f 100644 --- a/src/Layers/APAC/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al +++ b/src/Layers/APAC/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al @@ -6479,6 +6479,9 @@ codeunit 134920 "ERM General Journal UT" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.UpdateLocalData(); LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); @@ -7574,4 +7577,3 @@ codeunit 134920 "ERM General Journal UT" IsHandled := true; end; } - diff --git a/src/Layers/APAC/Tests/Prepayment/ERMPrepaymentII.Codeunit.al b/src/Layers/APAC/Tests/Prepayment/ERMPrepaymentII.Codeunit.al index be7ad2bb239..514e712534e 100644 --- a/src/Layers/APAC/Tests/Prepayment/ERMPrepaymentII.Codeunit.al +++ b/src/Layers/APAC/Tests/Prepayment/ERMPrepaymentII.Codeunit.al @@ -2694,7 +2694,6 @@ codeunit 134101 "ERM Prepayment II" GenJournalLine.Modify(true); LibraryERM.PostGeneralJnlLine(GenJournalLine); end; - local procedure SelectGenJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch") begin // Select General Journal Batch and clear General Journal Lines to make sure that no line exist before creating diff --git a/src/Layers/CH/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al b/src/Layers/CH/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al index c81c9d60800..31ef248f143 100644 --- a/src/Layers/CH/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al +++ b/src/Layers/CH/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al @@ -6287,6 +6287,9 @@ codeunit 134920 "ERM General Journal UT" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.UpdateLocalData(); LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); @@ -7372,4 +7375,3 @@ codeunit 134920 "ERM General Journal UT" IsHandled := true; end; } - diff --git a/src/Layers/CZ/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al b/src/Layers/CZ/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al index 4ed0a80f174..8ec73b78b86 100644 --- a/src/Layers/CZ/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al +++ b/src/Layers/CZ/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al @@ -6483,6 +6483,9 @@ codeunit 134920 "ERM General Journal UT" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.UpdateLocalData(); LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); @@ -7578,4 +7581,3 @@ codeunit 134920 "ERM General Journal UT" IsHandled := true; end; } - diff --git a/src/Layers/ES/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al b/src/Layers/ES/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al index 0f00c3467cc..0d3851871a9 100644 --- a/src/Layers/ES/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al +++ b/src/Layers/ES/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al @@ -6512,6 +6512,9 @@ codeunit 134920 "ERM General Journal UT" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.UpdateLocalData(); LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); @@ -7607,4 +7610,3 @@ codeunit 134920 "ERM General Journal UT" IsHandled := true; end; } - diff --git a/src/Layers/IT/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al b/src/Layers/IT/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al index 0044783f068..6ca6d94e75b 100644 --- a/src/Layers/IT/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al +++ b/src/Layers/IT/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al @@ -6478,6 +6478,9 @@ codeunit 134920 "ERM General Journal UT" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.UpdateLocalData(); LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); @@ -7573,4 +7576,3 @@ codeunit 134920 "ERM General Journal UT" IsHandled := true; end; } - diff --git a/src/Layers/NA/Tests/Prepayment/ERMPrepaymentII.Codeunit.al b/src/Layers/NA/Tests/Prepayment/ERMPrepaymentII.Codeunit.al index e514b0407b0..6cc9605ec93 100644 --- a/src/Layers/NA/Tests/Prepayment/ERMPrepaymentII.Codeunit.al +++ b/src/Layers/NA/Tests/Prepayment/ERMPrepaymentII.Codeunit.al @@ -2632,7 +2632,6 @@ codeunit 134101 "ERM Prepayment II" GenJournalLine.Modify(true); LibraryERM.PostGeneralJnlLine(GenJournalLine); end; - local procedure SelectGenJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch") begin // Select General Journal Batch and clear General Journal Lines to make sure that no line exist before creating diff --git a/src/Layers/W1/Tests/ERM/SpendRequestTests.Codeunit.al b/src/Layers/W1/Tests/ERM/SpendRequestTests.Codeunit.al index 11f5d08109a..ea889fe6e72 100644 --- a/src/Layers/W1/Tests/ERM/SpendRequestTests.Codeunit.al +++ b/src/Layers/W1/Tests/ERM/SpendRequestTests.Codeunit.al @@ -341,6 +341,37 @@ codeunit 134242 "Spend Request Tests" 'Deleting detail should reduce header total.'); end; + [Test] + procedure DeleteDetailLineDecrementsHeaderTotalExactlyOnce() + var + SpendRequest: Record "Spend Request"; + FirstSpendRequestDetail: Record "Spend Request Detail"; + RemainingSpendRequestDetail: Record "Spend Request Detail"; + begin + // [SCENARIO 646383] Real detail deletion applies each LCY delta exactly once without removing the other detail. + Initialize(); + + // [GIVEN] An open LCY request "R" initially has zero total and two details "D1" and "D2" worth 10 and 30. + CreateSpendRequest(SpendRequest); + VerifyDetailDeletionTotals(SpendRequest."No.", 0, 0); + CreateSpendRequestDetail(FirstSpendRequestDetail, SpendRequest."No.", 10); + CreateSpendRequestDetail(RemainingSpendRequestDetail, SpendRequest."No.", 30); + VerifyDetailDeletionTotals(SpendRequest."No.", 40, 2); + + // [WHEN] Deleting "D1" runs the production table trigger, not a page action or a permission test. + FirstSpendRequestDetail.Delete(true); + + // [THEN] "D2" survives and both its amount and the header total are 30. + RemainingSpendRequestDetail.Get(RemainingSpendRequestDetail."Spend Request No.", RemainingSpendRequestDetail."Line No."); + VerifyDetailDeletionTotals(SpendRequest."No.", 30, 1); + + // [WHEN] The remaining detail "D2" is deleted through its production trigger. + RemainingSpendRequestDetail.Delete(true); + + // [THEN] No details remain and the header total is exactly zero. + VerifyDetailDeletionTotals(SpendRequest."No.", 0, 0); + end; + [Test] [Scope('OnPrem')] procedure CannotInsertDetailOnReleasedRequest() @@ -827,4 +858,21 @@ codeunit 134242 "Spend Request Tests" // [THEN] An error is raised. Assert.ExpectedError('must have the status ' + Format(SpendRequest.Status::Open)); end; + + local procedure VerifyDetailDeletionTotals(SpendRequestNo: Code[20]; ExpectedAmount: Decimal; ExpectedLineCount: Integer) + var + SpendRequest: Record "Spend Request"; + SpendRequestDetail: Record "Spend Request Detail"; + begin + SpendRequest.Get(SpendRequestNo); + Assert.AreEqual(SpendRequest.Status::Open, SpendRequest.Status, 'Detail deletion must preserve the Open status.'); + Assert.AreEqual('', SpendRequest."Currency Code", 'The request must use LCY.'); + Assert.AreEqual(ExpectedAmount, SpendRequest."Total Expected Amount", 'The header amount must reflect each deleted detail exactly once.'); + Assert.AreEqual(ExpectedAmount, SpendRequest."Total Expected Amount (LCY)", 'The LCY header amount must reflect each deleted detail exactly once.'); + SpendRequestDetail.SetRange("Spend Request No.", SpendRequestNo); + Assert.AreEqual(ExpectedLineCount, SpendRequestDetail.Count(), 'Only the intended details must be deleted.'); + SpendRequestDetail.CalcSums("Expected Amount", "Expected Amount (LCY)"); + Assert.AreEqual(ExpectedAmount, SpendRequestDetail."Expected Amount", 'The remaining detail amounts must be unchanged.'); + Assert.AreEqual(ExpectedAmount, SpendRequestDetail."Expected Amount (LCY)", 'The remaining LCY detail amounts must be unchanged.'); + end; } \ No newline at end of file diff --git a/src/Layers/W1/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al b/src/Layers/W1/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al index 0bffda864c6..8c7dbafba22 100644 --- a/src/Layers/W1/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al +++ b/src/Layers/W1/Tests/General Journal/ERMGeneralJournalUT.Codeunit.al @@ -6478,6 +6478,9 @@ codeunit 134920 "ERM General Journal UT" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryERMCountryData.UpdateLocalData(); LibraryERMCountryData.CreateVATData(); LibraryERMCountryData.UpdateGeneralPostingSetup(); @@ -7573,4 +7576,3 @@ codeunit 134920 "ERM General Journal UT" IsHandled := true; end; } - diff --git a/src/Layers/W1/Tests/Graph/IRS1099CodeEntityE2ETest.Codeunit.al b/src/Layers/W1/Tests/Graph/IRS1099CodeEntityE2ETest.Codeunit.al index 80c99fa6f1c..68ba57ce87e 100644 --- a/src/Layers/W1/Tests/Graph/IRS1099CodeEntityE2ETest.Codeunit.al +++ b/src/Layers/W1/Tests/Graph/IRS1099CodeEntityE2ETest.Codeunit.al @@ -38,7 +38,9 @@ codeunit 135519 "IRS 1099 Code Entity E2E Test" if IsInitialized then exit; + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + IsInitialized := true; end; } - diff --git a/src/Layers/W1/Tests/Graph/WFWHSubscriptionE2ETests.Codeunit.al b/src/Layers/W1/Tests/Graph/WFWHSubscriptionE2ETests.Codeunit.al index f5b8e0f9859..7892b11735f 100644 --- a/src/Layers/W1/Tests/Graph/WFWHSubscriptionE2ETests.Codeunit.al +++ b/src/Layers/W1/Tests/Graph/WFWHSubscriptionE2ETests.Codeunit.al @@ -54,6 +54,9 @@ codeunit 135528 "WFWH Subscription E2E Tests" if IsInitialized then exit; + + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); IsInitialized := true; Commit(); @@ -1454,4 +1457,3 @@ codeunit 135528 "WFWH Subscription E2E Tests" exit(String); end; } - diff --git a/src/Layers/W1/Tests/Integration/ApiRoutesE2E.Codeunit.al b/src/Layers/W1/Tests/Integration/ApiRoutesE2E.Codeunit.al index 6744a7e1cb5..7149aab8024 100644 --- a/src/Layers/W1/Tests/Integration/ApiRoutesE2E.Codeunit.al +++ b/src/Layers/W1/Tests/Integration/ApiRoutesE2E.Codeunit.al @@ -13,6 +13,12 @@ codeunit 135548 "API Routes E2E" LibraryGraphMgt: Codeunit "Library - Graph Mgt"; ApiRoutesTxt: Label 'apiRoutes', Locked = true; + local procedure Initialize() + begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); + end; + [Test] [Scope('OnPrem')] procedure TestGetApiRoutesMany() @@ -21,6 +27,8 @@ codeunit 135548 "API Routes E2E" ResponseText: Text; begin // [SCENARIO] GET returns many routes in the payload + Initialize(); + // [GIVEN] apiRoutes URI without filters TargetURL := LibraryGraphMgt.CreateTargetURL('', PAGE::"API Routes", ApiRoutesTxt); @@ -39,6 +47,8 @@ codeunit 135548 "API Routes E2E" ResponseText: Text; begin // [SCENARIO] GET returns a single route in the payload + Initialize(); + // [GIVEN] apiRoutes URI for a single route TargetURL := LibraryGraphMgt.CreateTargetURL('''beta''', PAGE::"API Routes", ApiRoutesTxt); @@ -57,6 +67,8 @@ codeunit 135548 "API Routes E2E" ResponseText: Text; begin // [SCENARIO] POST is not allowed for apiRoutes + Initialize(); + // [GIVEN] apiRoutes URI for a single route TargetURL := LibraryGraphMgt.CreateTargetURL('', PAGE::"API Routes", ApiRoutesTxt); @@ -75,6 +87,8 @@ codeunit 135548 "API Routes E2E" ResponseText: Text; begin // [SCENARIO] PATCH is not allowed for apiRoutes + Initialize(); + // [GIVEN] apiRoutes URI for a single route TargetURL := LibraryGraphMgt.CreateTargetURL('''beta''', PAGE::"API Routes", ApiRoutesTxt); @@ -93,6 +107,8 @@ codeunit 135548 "API Routes E2E" ResponseText: Text; begin // [SCENARIO] DELETE is not allowed for apiRoutes + Initialize(); + // [GIVEN] apiRoutes URI for a single route TargetURL := LibraryGraphMgt.CreateTargetURL('''beta''', PAGE::"API Routes", ApiRoutesTxt); @@ -103,4 +119,3 @@ codeunit 135548 "API Routes E2E" Assert.ExpectedError('400 (BadRequest)'); end; } - diff --git a/src/Layers/W1/Tests/Integration/WebhookLogsE2E.Codeunit.al b/src/Layers/W1/Tests/Integration/WebhookLogsE2E.Codeunit.al index a5aad9c9707..5771fde4b9d 100644 --- a/src/Layers/W1/Tests/Integration/WebhookLogsE2E.Codeunit.al +++ b/src/Layers/W1/Tests/Integration/WebhookLogsE2E.Codeunit.al @@ -119,6 +119,8 @@ codeunit 135547 "Webhook Logs E2E" local procedure Initialize() begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); CleanActivityLogs(); AddActivityLog('first', 'red'); AddActivityLog('second', 'yellow'); @@ -153,4 +155,3 @@ codeunit 135547 "Webhook Logs E2E" ActivityLog.DeleteAll(); end; } - diff --git a/src/Layers/W1/Tests/Misc/APITestAuthHTTPTests.Codeunit.al b/src/Layers/W1/Tests/Misc/APITestAuthHTTPTests.Codeunit.al new file mode 100644 index 00000000000..e1575916b41 --- /dev/null +++ b/src/Layers/W1/Tests/Misc/APITestAuthHTTPTests.Codeunit.al @@ -0,0 +1,93 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +#pragma warning disable AA0247 + +codeunit 139496 "API Test Auth HTTP Tests" +{ + // A separate codeunit ends the URL tests' metadata transaction before making HTTP requests. + Subtype = Test; + TestPermissions = Disabled; + + var + Assert: Codeunit Assert; + LibraryGraphMgt: Codeunit "Library - Graph Mgt"; + FirstHttpWebRequestMgt: Codeunit "Http Web Request Mgt."; + SecondHttpWebRequestMgt: Codeunit "Http Web Request Mgt."; + + [Test] + procedure MicrosoftAuthenticationRespectsServerAuthMode() + var + EnvironmentInfo: Codeunit "Environment Information"; + TargetURL: Text; + ResponseCode: Integer; + ExpectedAmbientResponseCode: Integer; + begin + // [SCENARIO] Authentication supplies UserPassword credentials or preserves ambient Windows credentials + Initialize(); + + // [GIVEN] An OnPrem service accepts configured UserPassword credentials or authorized ambient Windows credentials + Assert.IsFalse(EnvironmentInfo.IsSaaSInfrastructure(), 'This HTTP scenario requires an OnPrem test environment.'); + ExpectedAmbientResponseCode := GetExpectedAmbientResponseCode(); + TargetURL := GetUrl(ClientType::ODataV4); + + // [WHEN] The default provider sends a real request to the authenticated OData service document + LibraryGraphMgt.InitializeWebRequestWithURL(FirstHttpWebRequestMgt, TargetURL); + ResponseCode := ExecuteRequest(FirstHttpWebRequestMgt); + + // [THEN] Only a Windows-authenticated service accepts ambient credentials + Assert.AreEqual(ExpectedAmbientResponseCode, ResponseCode, 'The default provider must respect the server authentication mode.'); + + // [WHEN] The Microsoft provider configures a new request to the same endpoint + LibraryGraphMgt.SetAuthenticationProvider(Enum::"API Test Authentication"::"Microsoft Test Environment"); + LibraryGraphMgt.InitializeWebRequestWithURL(SecondHttpWebRequestMgt, TargetURL); + ResponseCode := ExecuteRequest(SecondHttpWebRequestMgt); + + // [THEN] Configured UserPassword credentials or preserved Windows credentials authenticate the request + Assert.AreEqual(200, ResponseCode, 'The Microsoft provider must authenticate without disrupting ambient Windows credentials.'); + + // [WHEN] Authentication is deselected and another request is created + LibraryGraphMgt.SetAuthenticationProvider(Enum::"API Test Authentication"::None); + LibraryGraphMgt.InitializeWebRequestWithURL(FirstHttpWebRequestMgt, TargetURL); + ResponseCode := ExecuteRequest(FirstHttpWebRequestMgt); + + // [THEN] Configured credentials do not leak and ambient Windows authentication remains available + Assert.AreEqual(ExpectedAmbientResponseCode, ResponseCode, 'Deselecting the provider must restore the server authentication mode.'); + end; + + local procedure Initialize() + begin + Clear(LibraryGraphMgt); + Clear(FirstHttpWebRequestMgt); + Clear(SecondHttpWebRequestMgt); + end; + + local procedure GetExpectedAmbientResponseCode(): Integer + var + SecurityGroup: Codeunit "Security Group"; + begin + if SecurityGroup.IsWindowsAuthentication() then + exit(200); + + exit(401); + end; + + local procedure ExecuteRequest(var HttpWebRequestMgt: Codeunit "Http Web Request Mgt.") ResponseCode: Integer + var + TempBlob: Codeunit "Temp Blob"; + HttpStatusCode: DotNet HttpStatusCode; + ResponseHeaders: DotNet NameValueCollection; + ErrorMessage: Text; + ErrorDetails: Text; + Successful: Boolean; + begin + HttpWebRequestMgt.DisableUI(); + HttpWebRequestMgt.SetReturnType('application/json'); + Successful := HttpWebRequestMgt.SendRequestAndReadResponse(TempBlob, ErrorMessage, ErrorDetails, HttpStatusCode, ResponseHeaders); + Assert.IsFalse(IsNull(HttpStatusCode), 'The service must return an HTTP status, not a transport failure.'); + ResponseCode := HttpStatusCode; + Assert.AreEqual(ResponseCode = 200, Successful, 'The response status must agree with the transport result.'); + end; +} diff --git a/src/Layers/W1/Tests/Prepayment/ERMPrepaymentII.Codeunit.al b/src/Layers/W1/Tests/Prepayment/ERMPrepaymentII.Codeunit.al index 27e8b022b74..ac9aa24db4e 100644 --- a/src/Layers/W1/Tests/Prepayment/ERMPrepaymentII.Codeunit.al +++ b/src/Layers/W1/Tests/Prepayment/ERMPrepaymentII.Codeunit.al @@ -2575,7 +2575,6 @@ codeunit 134101 "ERM Prepayment II" GenJournalLine.Modify(true); LibraryERM.PostGeneralJnlLine(GenJournalLine); end; - local procedure SelectGenJournalBatch(var GenJournalBatch: Record "Gen. Journal Batch") begin // Select General Journal Batch and clear General Journal Lines to make sure that no line exist before creating @@ -3145,4 +3144,3 @@ codeunit 134101 "ERM Prepayment II" PurchaseHeader.TestField(Status, ExpectedStatus); end; } - diff --git a/src/Layers/W1/Tests/Report/ReportInboxAPIE2E.Codeunit.al b/src/Layers/W1/Tests/Report/ReportInboxAPIE2E.Codeunit.al index 01905a48000..daa0a0e2ec9 100644 --- a/src/Layers/W1/Tests/Report/ReportInboxAPIE2E.Codeunit.al +++ b/src/Layers/W1/Tests/Report/ReportInboxAPIE2E.Codeunit.al @@ -443,6 +443,8 @@ codeunit 135549 "Report Inbox API E2E" var Company: Record Company; begin + LibraryGraphMgt.SetAuthenticationProvider( + Enum::"API Test Authentication"::"Microsoft Test Environment"); if Company.FindSet() then repeat DeleteEntriesIn(Company.Name, UserId()); diff --git a/src/Layers/W1/Tests/TestLibraries/LibraryGraphDocumentTools.Codeunit.al b/src/Layers/W1/Tests/TestLibraries/LibraryGraphDocumentTools.Codeunit.al index cc281f04818..d89183ab2e0 100644 --- a/src/Layers/W1/Tests/TestLibraries/LibraryGraphDocumentTools.Codeunit.al +++ b/src/Layers/W1/Tests/TestLibraries/LibraryGraphDocumentTools.Codeunit.al @@ -1,10 +1,6 @@ codeunit 130619 "Library - Graph Document Tools" { - trigger OnRun() - begin - end; - var LibraryApplicationArea: Codeunit "Library - Application Area"; LibrarySales: Codeunit "Library - Sales"; @@ -895,4 +891,3 @@ codeunit 130619 "Library - Graph Document Tools" Assert.AreEqual(ExpectedDiscountAmount, ActualInvoiceDiscountAmount, 'Invoice discount amount was not set'); end; } - diff --git a/src/Layers/W1/Tests/TestLibraries/LibraryGraphJournalLines.Codeunit.al b/src/Layers/W1/Tests/TestLibraries/LibraryGraphJournalLines.Codeunit.al index ea303197684..7ec14a67541 100644 --- a/src/Layers/W1/Tests/TestLibraries/LibraryGraphJournalLines.Codeunit.al +++ b/src/Layers/W1/Tests/TestLibraries/LibraryGraphJournalLines.Codeunit.al @@ -1,10 +1,6 @@ codeunit 130622 "Library - Graph Journal Lines" { - trigger OnRun() - begin - end; - var LibraryERM: Codeunit "Library - ERM"; LibrarySales: Codeunit "Library - Sales"; @@ -321,4 +317,3 @@ codeunit 130622 "Library - Graph Journal Lines" Assert.AreEqual(NewDate, GenJournalLine."Posting Date", 'Journal Line ' + PostingDateNameTxt + ' should be changed'); end; } - diff --git a/src/Layers/W1/Tests/TestLibraries/LibraryGraphMgt.Codeunit.al b/src/Layers/W1/Tests/TestLibraries/LibraryGraphMgt.Codeunit.al index 38b8c0f8bf8..bc37687e68c 100644 --- a/src/Layers/W1/Tests/TestLibraries/LibraryGraphMgt.Codeunit.al +++ b/src/Layers/W1/Tests/TestLibraries/LibraryGraphMgt.Codeunit.al @@ -31,6 +31,12 @@ codeunit 130618 "Library - Graph Mgt" AuthenticationProviderResolved := true; end; + /// Sets the work date to November 15 in the current year to stay within test-license date limits. + procedure SetLicenseSafeWorkDate() + begin + WorkDate := DMY2Date(15, 11, Date2DMY(Today, 3)); + end; + procedure EnsureWebServiceExist(ServiceNameTxt: Text[240]; PageNumber: Integer) var WebService: Record "Web Service";