Tests/Varibill.SourceCollector.Core.Tests.ps1

# Requires Pester 5
# Save as Varibill.SourceCollector.Tests.ps1

# Always prefer Pester 5.x instead of the built-in 3.x

Import-Module "$PSScriptRoot/../Varibill.SourceCollector.Core.psm1" -Force

Describe "Varibill SourceData Module" {

    BeforeAll {
        $script:TempPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "VaribillTests"
        if (Test-Path $script:TempPath) { Remove-Item $script:TempPath -Recurse -Force }
        New-Item -Path $script:TempPath -ItemType Directory | Out-Null

        # Ensure subfolders exist
        New-Item -Path (Join-Path $script:TempPath "Unrated") -ItemType Directory | Out-Null
        New-Item -Path (Join-Path $script:TempPath "Rated") -ItemType Directory | Out-Null
    }

    Context "UnratedSourceData" {

        It "can create an instance via constructor" {
            $unrated = New-UnratedSourceData -SourceCollectorAPI "https://test.api" `
                                             -TenantKey ([guid]::NewGuid()) `
                                             -SourceCollectorKey ([guid]::NewGuid()) `
                                             -SourceCollectorSecret "secret" `
                                             -SourceCollectorPath $script:TempPath `
                                             -MaxRecordsPerFile 10
            $unrated.GetType().Name | Should -Be 'UnratedSourceData'
        }

        It "can create an instance via New-UnratedSourceData function" {
            $unrated = New-UnratedSourceData -SourceCollectorAPI "https://test.api" `
                                             -TenantKey ([guid]::NewGuid()) `
                                             -SourceCollectorKey ([guid]::NewGuid()) `
                                             -SourceCollectorSecret "secret" `
                                             -SourceCollectorPath $script:TempPath
            $unrated.GetType().Name | Should -Be 'UnratedSourceData'
        }

        It "can add records" {
            $unrated = New-UnratedSourceData -SourceCollectorAPI "https://test.api" `
                                             -TenantKey ([guid]::NewGuid()) `
                                             -SourceCollectorKey ([guid]::NewGuid()) `
                                             -SourceCollectorSecret "secret" `
                                             -SourceCollectorPath $script:TempPath
            $unrated.AddUnratedSourceData("Client1","Prod1","Rec1","UID1",(Get-Date),5,"Tag1")
            $unrated.Records.Count | Should -Be 1
        }

        It "saves records to .rdy files" {
            $unrated = New-UnratedSourceData -SourceCollectorAPI "https://test.api" `
                                             -TenantKey ([guid]::NewGuid()) `
                                             -SourceCollectorKey ([guid]::NewGuid()) `
                                             -SourceCollectorSecret "secret" `
                                             -SourceCollectorPath $script:TempPath `
                                             -MaxRecordsPerFile 2
            1..5 | ForEach-Object { $unrated.AddUnratedSourceData("Client$_","Prod$_","Rec$_","UID$_",(Get-Date),$_,"Tag$_") }

            $unrated.SaveData()
            $files = Get-ChildItem -Path (Join-Path $script:TempPath "Unrated") -Filter "*.rdy"
            $files.Count | Should -Be 3
        }

        It "posts data successfully (mocked)" {
            $unrated = New-UnratedSourceData -SourceCollectorAPI "https://test.api" `
                                             -TenantKey ([guid]::NewGuid()) `
                                             -SourceCollectorKey ([guid]::NewGuid()) `
                                             -SourceCollectorSecret "secret" `
                                             -SourceCollectorPath $script:TempPath
            $unrated.AddUnratedSourceData("Client1","Prod1","Rec1","UID1",(Get-Date),5,"Tag1")

            # Mock Invoke-WebRequest inside the module
            Mock -CommandName Invoke-WebRequest -ModuleName 'Varibill.SourceCollector.Core' -MockWith {
                return [PSCustomObject]@{
                    StatusCode = 201
                    Content    = '{"result":"ok"}'
                }
            }

            $unrated.PostSourceData()
            $files = Get-ChildItem -Path (Join-Path $script:TempPath "Unrated") -Filter "*.json"
            $files.Count | Should -BeGreaterThan 0
        }

        It "does not rename .rdy file on failed post (mocked)" {
            $unrated = New-UnratedSourceData -SourceCollectorAPI "https://test.api" `
                                             -TenantKey ([guid]::NewGuid()) `
                                             -SourceCollectorKey ([guid]::NewGuid()) `
                                             -SourceCollectorSecret "secret" `
                                             -SourceCollectorPath $script:TempPath
            $unrated.AddUnratedSourceData("Client1","Prod1","Rec1","UID1",(Get-Date),5,"Tag1")

            Mock -CommandName Invoke-WebRequest -ModuleName 'Varibill.SourceCollector.Core' -MockWith {
                return [PSCustomObject]@{
                    StatusCode = 500
                    Content    = '{"error":"internal"}'
                }
            }

            $unrated.PostSourceData()
            $files = Get-ChildItem -Path (Join-Path $script:TempPath "Unrated") -Filter "*.rdy"
            $files.Count | Should -Be 1
        }
    }

    Context "RatedSourceData" {

        It "can create an instance via constructor" {
            $rated = New-RatedSourceData -SourceCollectorAPI "https://test.api" `
                                         -TenantKey ([guid]::NewGuid()) `
                                         -SourceCollectorKey ([guid]::NewGuid()) `
                                         -SourceCollectorSecret "secret" `
                                         -SourceCollectorPath $script:TempPath `
                                         -MaxRecordsPerFile 10
             $rated.GetType().Name | Should -Be 'RatedSourceData'
         }

        It "can create an instance via New-RatedSourceData function" {
            $rated = New-RatedSourceData -SourceCollectorAPI "https://test.api" `
                                         -TenantKey ([guid]::NewGuid()) `
                                         -SourceCollectorKey ([guid]::NewGuid()) `
                                         -SourceCollectorSecret "secret" `
                                         -SourceCollectorPath $script:TempPath
            $rated.GetType().Name | Should -Be 'RatedSourceData'
        }

        It "can add records" {
            $rated = New-RatedSourceData -SourceCollectorAPI "https://test.api" `
                                         -TenantKey ([guid]::NewGuid()) `
                                         -SourceCollectorKey ([guid]::NewGuid()) `
                                         -SourceCollectorSecret "secret" `
                                         -SourceCollectorPath $script:TempPath
            $rated.AddRatedSourceData("Client1","Prod1","Rec1","UID1",(Get-Date),10,20,5,"Tag1")
            $rated.Records.Count | Should -Be 1
        }

        It "saves records to .rdy files" {
            $rated = New-RatedSourceData -SourceCollectorAPI "https://test.api" `
                                         -TenantKey ([guid]::NewGuid()) `
                                         -SourceCollectorKey ([guid]::NewGuid()) `
                                         -SourceCollectorSecret "secret" `
                                         -SourceCollectorPath $script:TempPath `
                                         -MaxRecordsPerFile 2
            1..5 | ForEach-Object { $rated.AddRatedSourceData("Client$_","Prod$_","Rec$_","UID$_",(Get-Date),$_,$_ * 2,$_ * 1.5,"Tag$_") }

            $rated.SaveData()
            $files = Get-ChildItem -Path (Join-Path $script:TempPath "Rated") -Filter "*.rdy"
            $files.Count | Should -Be 3
        }

        It "posts data successfully (mocked)" {
            $rated = New-RatedSourceData -SourceCollectorAPI "https://test.api" `
                                         -TenantKey ([guid]::NewGuid()) `
                                         -SourceCollectorKey ([guid]::NewGuid()) `
                                         -SourceCollectorSecret "secret" `
                                         -SourceCollectorPath $script:TempPath
            $rated.AddRatedSourceData("Client1","Prod1","Rec1","UID1",(Get-Date),10,20,5,"Tag1")

            Mock -CommandName Invoke-WebRequest -ModuleName 'Varibill.SourceCollector.Core' -MockWith {
                return [PSCustomObject]@{
                    StatusCode = 200
                    Content    = '{"result":"ok"}'
                }
            }

            $rated.PostSourceData()
            $files = Get-ChildItem -Path (Join-Path $script:TempPath "Rated") -Filter "*.json"
            $files.Count | Should -BeGreaterThan 0
        }

        It "does not rename .rdy file on failed post (mocked)" {
            $rated = New-RatedSourceData -SourceCollectorAPI "https://test.api" `
                                         -TenantKey ([guid]::NewGuid()) `
                                         -SourceCollectorKey ([guid]::NewGuid()) `
                                         -SourceCollectorSecret "secret" `
                                         -SourceCollectorPath $script:TempPath
            $rated.AddRatedSourceData("Client1","Prod1","Rec1","UID1",(Get-Date),10,20,5,"Tag1")

            Mock -CommandName Invoke-WebRequest -ModuleName 'Varibill.SourceCollector.Core' -MockWith {
                return [PSCustomObject]@{
                    StatusCode = 400
                    Content    = '{"error":"bad request"}'
                }
            }

            $rated.PostSourceData()
            $files = Get-ChildItem -Path (Join-Path $script:TempPath "Rated") -Filter "*.rdy"
            $files.Count | Should -Be 1
        }
    }

    AfterAll {
        if (Test-Path $script:TempPath) { Remove-Item $script:TempPath -Recurse -Force }
    }
}