diff --git a/Scripts/Sales Reconciliation.js b/Scripts/Sales Reconciliation.js index b7bbcaa..16677c7 100644 --- a/Scripts/Sales Reconciliation.js +++ b/Scripts/Sales Reconciliation.js @@ -1,5 +1,5 @@ -select CONCAT(YEAR(transactiondate),'-', FORMAT(transactiondate, 'MM')), +/*select CONCAT(YEAR(transactiondate),'-', FORMAT(transactiondate, 'MM')), count(*) as 'count', SUM(case [transaction].TransactionType WHEN 'Logon' THEN 1 @@ -20,7 +20,7 @@ SUM([transaction].TransactionAmount) as totalamount from [transaction] group by CONCAT(YEAR(transactiondate),'-', FORMAT(transactiondate, 'MM')) order by CONCAT(YEAR(transactiondate),'-', FORMAT(transactiondate, 'MM')) asc - +*/ fromAll() .when({ diff --git a/Scripts/Scavenge.xml b/Scripts/Scavenge.xml new file mode 100644 index 0000000..71db543 Binary files /dev/null and b/Scripts/Scavenge.xml differ diff --git a/Scripts/Tests/Scavenge.Tests.ps1 b/Scripts/Tests/Scavenge.Tests.ps1 new file mode 100644 index 0000000..47957be --- /dev/null +++ b/Scripts/Tests/Scavenge.Tests.ps1 @@ -0,0 +1,78 @@ +Describe 'scavenge.ps1' { + It 'posts to /admin/scavenge after trimming a trailing slash from BaseUrl' { + $scriptUnderTest = (Resolve-Path (Join-Path (Split-Path $PSScriptRoot -Parent) 'scavenge.ps1')).Path + $expectedUri = 'http://localhost:2113/admin/scavenge' + $captured = [pscustomobject]@{ + Count = 0 + Uri = $null + Headers = $null + } + + Mock Invoke-RestMethod { + $captured.Count++ + $captured.Uri = $Uri + $captured.Headers = $Headers + @{ status = 'ok' } + } -ParameterFilter { + $Method -eq 'Post' + } + + & $scriptUnderTest -BaseUrl 'http://localhost:2113/' + + $captured.Count | Should -Be 1 + $captured.Uri | Should -Be $expectedUri + $captured.Headers.Accept | Should -Be 'application/json' + $captured.Headers.'Content-Type' | Should -Be 'application/json' + $captured.Headers.ContainsKey('Authorization') | Should -BeFalse + } + + It 'adds a Basic Authorization header when username and password are both provided' { + $scriptUnderTest = (Resolve-Path (Join-Path (Split-Path $PSScriptRoot -Parent) 'scavenge.ps1')).Path + $expectedUri = 'http://localhost:2113/admin/scavenge' + $expectedAuth = 'Basic ' + [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes('alice:secret')) + $captured = [pscustomobject]@{ + Count = 0 + Uri = $null + Headers = $null + } + + Mock Invoke-RestMethod { + $captured.Count++ + $captured.Uri = $Uri + $captured.Headers = $Headers + @{ status = 'ok' } + } -ParameterFilter { + $Method -eq 'Post' + } + + & $scriptUnderTest -BaseUrl 'http://localhost:2113' -Username 'alice' -Password 'secret' + + $captured.Count | Should -Be 1 + $captured.Uri | Should -Be $expectedUri + $captured.Headers.Authorization | Should -Be $expectedAuth + } + + It 'does not add an Authorization header when only one credential is supplied' { + $scriptUnderTest = (Resolve-Path (Join-Path (Split-Path $PSScriptRoot -Parent) 'scavenge.ps1')).Path + $captured = [pscustomobject]@{ + Count = 0 + Uri = $null + Headers = $null + } + + Mock Invoke-RestMethod { + $captured.Count++ + $captured.Uri = $Uri + $captured.Headers = $Headers + @{ status = 'ok' } + } -ParameterFilter { + $Method -eq 'Post' + } + + & $scriptUnderTest -BaseUrl 'http://localhost:2113' -Username 'alice' + + $captured.Count | Should -Be 1 + $captured.Uri | Should -Be 'http://localhost:2113/admin/scavenge' + $captured.Headers.ContainsKey('Authorization') | Should -BeFalse + } +} diff --git a/Scripts/scavenge.ps1 b/Scripts/scavenge.ps1 new file mode 100644 index 0000000..ae5e2db --- /dev/null +++ b/Scripts/scavenge.ps1 @@ -0,0 +1,28 @@ +param( + [string]$BaseUrl = "http://localhost:2113", + [string]$Username, + [string]$Password +) + +$BaseUrl = $BaseUrl.TrimEnd('/') +$uri = "$BaseUrl/admin/scavenge" + +$headers = @{ + Accept = 'application/json' + 'Content-Type' = 'application/json' +} + +if ($Username -and $Password) { + $pair = "$Username`:$Password" + $bytes = [System.Text.Encoding]::ASCII.GetBytes($pair) + $encoded = [Convert]::ToBase64String($bytes) + $headers['Authorization'] = "Basic $encoded" +} + +try { + Invoke-RestMethod -Method Post -Uri $uri -Headers $headers +} +catch { + Write-Error "POST to $uri failed: $($_.Exception.Message)" + exit 1 +} \ No newline at end of file diff --git a/docs/superpowers/plans/2026-07-09-scavenge-tests.md b/docs/superpowers/plans/2026-07-09-scavenge-tests.md new file mode 100644 index 0000000..0cf3c87 --- /dev/null +++ b/docs/superpowers/plans/2026-07-09-scavenge-tests.md @@ -0,0 +1,113 @@ +# Scavenge Script Tests Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add focused unit tests for `Scripts/scavenge.ps1` that cover request construction and authentication header behavior. + +**Architecture:** Keep the existing script unchanged unless a test exposes a real behavioral gap. Add one Pester test file alongside the existing script tests so the new coverage stays in the same style and location as the current PowerShell tests. + +**Tech Stack:** PowerShell, Pester + +## Global Constraints + +- Keep tests local and deterministic; do not hit the real `http://localhost:2113` service. +- Follow the existing script-test style in `Scripts/Tests/Invoke-DailySettlementProcessing.Tests.ps1`. + +--- + +### Task 1: Add scavenge script tests + +**Files:** +- Create: `Scripts/Tests/Scavenge.Tests.ps1` + +**Interfaces:** +- Consumes: `Scripts/scavenge.ps1` +- Produces: Pester coverage for the POST target URI and auth header branching + +- [ ] **Step 1: Write the test file** + +```powershell +Describe 'scavenge.ps1' { + It 'posts to /admin/scavenge after trimming a trailing slash from BaseUrl' { + $scriptUnderTest = (Resolve-Path (Join-Path (Split-Path $PSScriptRoot -Parent) 'scavenge.ps1')).Path + $expectedUri = 'http://localhost:2113/admin/scavenge' + $captured = [pscustomobject]@{ + Count = 0 + Uri = $null + Headers = $null + } + + Mock Invoke-RestMethod { + $captured.Count++ + $captured.Uri = $Uri + $captured.Headers = $Headers + @{ status = 'ok' } + } -ParameterFilter { + $Method -eq 'Post' + } + + & $scriptUnderTest -BaseUrl 'http://localhost:2113/' + + $captured.Count | Should -Be 1 + $captured.Uri | Should -Be $expectedUri + $captured.Headers.Accept | Should -Be 'application/json' + $captured.Headers.'Content-Type' | Should -Be 'application/json' + $captured.Headers.ContainsKey('Authorization') | Should -BeFalse + } + + It 'adds a Basic Authorization header when username and password are both provided' { + $scriptUnderTest = (Resolve-Path (Join-Path (Split-Path $PSScriptRoot -Parent) 'scavenge.ps1')).Path + $expectedUri = 'http://localhost:2113/admin/scavenge' + $expectedAuth = 'Basic ' + [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes('alice:secret')) + $captured = [pscustomobject]@{ + Count = 0 + Uri = $null + Headers = $null + } + + Mock Invoke-RestMethod { + $captured.Count++ + $captured.Uri = $Uri + $captured.Headers = $Headers + @{ status = 'ok' } + } -ParameterFilter { + $Method -eq 'Post' + } + + & $scriptUnderTest -BaseUrl 'http://localhost:2113' -Username 'alice' -Password 'secret' + + $captured.Count | Should -Be 1 + $captured.Uri | Should -Be $expectedUri + $captured.Headers.Authorization | Should -Be $expectedAuth + } + + It 'does not add an Authorization header when only one credential is supplied' { + $scriptUnderTest = (Resolve-Path (Join-Path (Split-Path $PSScriptRoot -Parent) 'scavenge.ps1')).Path + $captured = [pscustomobject]@{ + Count = 0 + Uri = $null + Headers = $null + } + + Mock Invoke-RestMethod { + $captured.Count++ + $captured.Uri = $Uri + $captured.Headers = $Headers + @{ status = 'ok' } + } -ParameterFilter { + $Method -eq 'Post' + } + + & $scriptUnderTest -BaseUrl 'http://localhost:2113' -Username 'alice' + + $captured.Count | Should -Be 1 + $captured.Uri | Should -Be 'http://localhost:2113/admin/scavenge' + $captured.Headers.ContainsKey('Authorization') | Should -BeFalse + } +} +``` + +- [ ] **Step 2: Run the test file** + +Run: `Invoke-Pester Scripts/Tests/Scavenge.Tests.ps1` +Expected: all three tests pass