Files

210 lines
9.7 KiB
PowerShell

# Tests\ADService.Tests.ps1
# Unit & Integration Tests for ADService Module
BeforeAll {
$scriptDir = Split-Path -Parent $PSScriptRoot
. (Join-Path $scriptDir "Modules\ADService.ps1")
}
Describe "ADService Unit Tests" -Tag "Mock", "Unit" {
Context "LDAPS Path Construction & String Interpolation" {
It "constructs standard LDAP URI on port 389 when UseLdaps is false" {
$res = Test-ADConnection -DomainController "dc01.corp.local" -BaseOU "DC=corp,DC=local" -UseLdaps $false
$res.LdapPath | Should -Be "LDAP://dc01.corp.local/DC=corp,DC=local"
}
It "constructs LDAPS URI on port 636 without losing DC variable expansion" {
# Regression test for scope interpolation bug where $dc:636 resulted in LDAP://
$res = Test-ADConnection -DomainController "dc01.corp.local" -BaseOU "DC=corp,DC=local" -UseLdaps $true
$res.LdapPath | Should -Be "LDAP://dc01.corp.local:636/DC=corp,DC=local"
$res.LdapPath | Should -Not -Be "LDAP:///DC=corp,DC=local"
}
It "defaults to RootDSE path when BaseOU is empty" {
$res = Test-ADConnection -DomainController "dc01.corp.local" -BaseOU "" -UseLdaps $false
$res.LdapPath | Should -Be "LDAP://dc01.corp.local/RootDSE"
}
It "gracefully reports failure when DC is unreachable without throwing unhandled exception" {
$res = Test-ADConnection -DomainController "nonexistent-dc.corp.local" -BaseOU "DC=corp,DC=local"
$res.Success | Should -BeFalse
$res.Message | Should -Match "AD 연결 실패"
}
}
Context "Mock User Directory & Filtering" {
It "retrieves all 5 sample users when filter is empty in demo mode" {
$users = Get-ADSampleUsers
$users.Count | Should -Be 5
$users[0].IsLive | Should -BeFalse
}
It "filters users by SamAccountName substring" {
$matched = Get-ADSampleUsers -Filter "gdhong"
@($matched).Count | Should -Be 1
$matched[0].SamAccountName | Should -Be "gdhong"
$matched[0].DisplayName | Should -Be "홍길동"
}
It "filters users by Korean DisplayName" {
$matched = Get-ADSampleUsers -Filter "김철수"
@($matched).Count | Should -Be 1
$matched[0].SamAccountName | Should -Be "cskim"
$matched[0].Department | Should -Be "데이터플랫폼팀"
}
It "filters users by Department name" {
$matched = Get-ADSampleUsers -Filter "보안관제팀"
@($matched).Count | Should -Be 1
$matched[0].SamAccountName | Should -Be "yylee"
$matched[0].IsLocked | Should -BeTrue
$matched[0].StatusText | Should -Be "잠김"
}
It "returns empty collection when filter does not match any user" {
$matched = Get-ADSampleUsers -Filter "NonExistentFilterKeyword999"
@($matched).Count | Should -Be 0
}
It "verifies complete AD user attributes on sample collection" {
$users = Get-ADSampleUsers
foreach ($u in $users) {
$u.SamAccountName | Should -Not -BeNullOrEmpty
$u.DisplayName | Should -Not -BeNullOrEmpty
$u.Department | Should -Not -BeNullOrEmpty
$u.UserPrincipalName | Should -Match "@"
$u.DistinguishedName | Should -Match "^CN="
}
}
It "invokes Get-ADUserList in demo mode and returns sample users" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$users = Get-ADUserList -Filter "" -Config $cfg
$users.Count | Should -Be 5
}
}
Context "Account Operations (Demo Simulation Mode)" {
It "simulates account unlock and reports success" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$res = Unlock-ADUserAccount -SamAccountName "yylee" -Config $cfg
$res.Success | Should -BeTrue
$res.Message | Should -Match "yylee"
$res.Message | Should -Match "잠금이 해제되었습니다"
}
It "simulates password reset with auto-generated temporary password" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$res = Reset-ADUserPassword -SamAccountName "gdhong" -Config $cfg
$res.Success | Should -BeTrue
$res.Message | Should -Match "gdhong"
$res.Message | Should -Match "Passw0rd!#"
}
It "simulates password reset with custom password" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$customPass = "CustomComplexPass!2026"
$res = Reset-ADUserPassword -SamAccountName "cskim" -NewPassword $customPass -Config $cfg
$res.Success | Should -BeTrue
$res.Message | Should -Match $customPass
}
It "simulates account state change to enabled" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$res = Set-ADUserAccountState -SamAccountName "mschoi" -Enable $true -Config $cfg
$res.Success | Should -BeTrue
$res.Message | Should -Match "활성화"
}
It "simulates account state change to disabled" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$res = Set-ADUserAccountState -SamAccountName "mschoi" -Enable $false -Config $cfg
$res.Success | Should -BeTrue
$res.Message | Should -Match "비활성화"
}
}
Context "Multi-DC Architecture & Replication Control" {
It "returns all 6 domain controllers across distributed sites" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$dcs = Get-ADDomainControllers -Config $cfg
$dcs.Count | Should -Be 6
$hostNames = @($dcs | ForEach-Object { $_.HostName })
$hostNames | Should -Contain "dc01.corp.local"
$hostNames | Should -Contain "dc02.corp.local"
$hostNames | Should -Contain "dc03.corp.local"
$hostNames | Should -Contain "dc04.corp.local"
$hostNames | Should -Contain "dc05.corp.local"
$hostNames | Should -Contain "dc06.corp.local"
$sites = @($dcs | ForEach-Object { $_.Site })
$sites | Should -Contain "Seoul-HQ"
$sites | Should -Contain "Pangyo-DC"
$sites | Should -Contain "Daejeon-DR"
$sites | Should -Contain "Azure-KOR"
}
It "identifies dc01.corp.local as Primary Domain Controller (PDC)" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$dcs = Get-ADDomainControllers -Config $cfg
$pdc = $dcs | Where-Object { $_.IsPdc -eq $true }
$pdc | Should -Not -BeNullOrEmpty
$pdc.HostName | Should -Be "dc01.corp.local"
}
It "directly binds to target DC when creating security group to bypass multi-DC replication lag" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false; BaseOU = "OU=SecurityGroups,DC=corp,DC=local" } }
$members = @("gdhong", "cskim", "yylee")
$res = New-ADSecurityGroupOnTargetDc -GroupName "Finance_Share_SecGroup" -GroupScope "Global" -TargetDc "dc04.corp.local" -Members $members -Config $cfg
$res.Success | Should -BeTrue
$res.TargetDc | Should -Be "dc04.corp.local"
$res.GroupDN | Should -Be "CN=Finance_Share_SecGroup,OU=SecurityGroups,DC=corp,DC=local"
$res.AddedMembers.Count | Should -Be 3
$res.Message | Should -Match "Direct DC Binding"
}
It "simulates targeted single-object replication to destination DC" {
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$res = Sync-ADObjectToTargetDc -ObjectDN "CN=HR_Share,OU=Groups,DC=corp,DC=local" -SourceDc "dc04.corp.local" -DestinationDc "dc01.corp.local" -Config $cfg
$res.Success | Should -BeTrue
$res.SourceDc | Should -Be "dc04.corp.local"
$res.DestinationDc | Should -Be "dc01.corp.local"
$res.Method | Should -Match "Targeted Replication"
$res.Message | Should -Match "즉시 단방향 복제"
}
It "verifies multi-DC site awareness and WAN replication delay isolation" {
# In a multi-site topology (Seoul, Pangyo, Daejeon, Azure),
# Direct binding to the NetApp-active DC guarantees 0-second replication lag
$cfg = @{ ActiveDirectory = @{ UseLive = $false } }
$dcs = Get-ADDomainControllers -Config $cfg
$siteMap = @{}
foreach ($dc in $dcs) {
if (-not $siteMap.ContainsKey($dc.Site)) { $siteMap[$dc.Site] = @() }
$siteMap[$dc.Site] += $dc.HostName
}
$siteMap.Keys.Count | Should -BeGreaterOrEqual 4
$siteMap["Pangyo-DC"] | Should -Contain "dc04.corp.local"
}
}
Context "Live Infrastructure Path & Connectivity Tests" -Tag "Live" {
It "safely handles unreachable live domain controller" {
$res = Test-ADConnection -DomainController "127.0.0.1:65532" -BaseOU "DC=corp,DC=local"
$res.Success | Should -BeFalse
$res.Message | Should -Match "AD 연결 실패"
}
It "gracefully fails over New-ADSecurityGroupOnTargetDc when live target DC is unreachable" {
$cfg = @{ ActiveDirectory = @{ UseLive = $true; Username = "test"; Password = "pwd"; UseLdaps = $false } }
$res = New-ADSecurityGroupOnTargetDc -GroupName "TestGroup" -TargetDc "127.0.0.1:65532" -Config $cfg
$res.Success | Should -BeFalse
$res.IsLive | Should -BeTrue
$res.Message | Should -Match "실패"
}
}
}