Skip to content

Commit 0b8c17d

Browse files
authored
Merge pull request #5 from cmbrose/more-unit-tests
More unit tests
2 parents baee6c4 + 6269f10 commit 0b8c17d

18 files changed

+2042
-104
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Release Notes
22
All notable changes and release history of the "cosmos-db" module will be documented in this file.
33

4+
## 1.7
5+
* Minor interface improvements
6+
47
## 1.6
58
* Adds `Use-CosmosDbInternalFlag` command to access some experimental features and debugging helpers
69
* Fixes support for extra query features in `Search-CosmosDbRecords` for DBs with more than one partition key range

cosmos-db/cosmos-db.psd1

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#
44
# Generated by: cmbrose
55
#
6-
# Generated on: 12/18/2020
6+
# Generated on: 12/27/2020
77
#
88

99
@{
@@ -12,7 +12,7 @@
1212
# RootModule = ''
1313

1414
# Version number of this module.
15-
ModuleVersion = '1.6'
15+
ModuleVersion = '1.7'
1616

1717
# Supported PSEditions
1818
# CompatiblePSEditions = @()

cosmos-db/cosmos-db.psm1

+56-38
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ Function Get-AuthorizationHeader([string]$ResourceGroup, [string]$SubscriptionId
127127
Function Get-CommonHeaders([string]$now, [string]$encodedAuthString, [string]$contentType="application/json", [bool]$isQuery=$false, [string]$PartitionKey=$null)
128128
{
129129
$headers = @{
130-
"x-ms-date"=$now;
130+
"x-ms-date" = $now;
131131
"x-ms-version" = $API_VERSION;
132132
"Authorization" = $encodedAuthString;
133133
"Cache-Control" = "No-Cache";
@@ -136,12 +136,12 @@ Function Get-CommonHeaders([string]$now, [string]$encodedAuthString, [string]$co
136136

137137
if ($isQuery)
138138
{
139-
$headers[ "x-ms-documentdb-isquery"] = "true"
139+
$headers["x-ms-documentdb-isquery"] = "true"
140140
}
141141

142142
if ($PartitionKey)
143143
{
144-
$headers["x-ms-documentdb-partitionkey"] = "[`"$requestPartitionKey`"]"
144+
$headers["x-ms-documentdb-partitionkey"] = "[`"$PartitionKey`"]"
145145
}
146146

147147
$headers
@@ -204,7 +204,7 @@ Function Invoke-CosmosDbApiRequestWithContinuation([string]$verb, [string]$url,
204204
}
205205
}
206206

207-
Function Get-PartitionKeyRanges
207+
Function Get-PartitionKeyRangesOrError
208208
(
209209
[parameter(Mandatory=$true)][string]$ResourceGroup,
210210
[parameter(Mandatory=$true)][string]$Database,
@@ -213,33 +213,40 @@ Function Get-PartitionKeyRanges
213213
[parameter(Mandatory=$true)][string]$SubscriptionId
214214
)
215215
{
216-
$baseUrl = Get-BaseDatabaseUrl $Database
217-
$collectionsUrl=Get-CollectionsUrl $Container $Collection
218-
$pkRangeUrl="$collectionsUrl/$PARTITIONKEYRANGE_TYPE"
216+
try
217+
{
218+
$baseUrl = Get-BaseDatabaseUrl $Database
219+
$collectionsUrl=Get-CollectionsUrl $Container $Collection
220+
$pkRangeUrl="$collectionsUrl/$PARTITIONKEYRANGE_TYPE"
219221

220-
$url = "$baseUrl/$pkRangeUrl"
222+
$url = "$baseUrl/$pkRangeUrl"
221223

222-
$cacheKey = $url
223-
$cacheResult = Get-CacheValue -Key $cacheKey -Cache $PARTITION_KEY_RANGE_CACHE
224-
if ($cacheResult)
225-
{
226-
return $cacheResult
227-
}
224+
$cacheKey = $url
225+
$cacheResult = Get-CacheValue -Key $cacheKey -Cache $PARTITION_KEY_RANGE_CACHE
226+
if ($cacheResult)
227+
{
228+
return $cacheResult
229+
}
228230

229-
$now = Get-Time
231+
$now = Get-Time
230232

231-
$encodedAuthString = Get-AuthorizationHeader -ResourceGroup $ResourceGroup -SubscriptionId $SubscriptionId -Database $Database -verb $GET_VERB -resourceType $PARTITIONKEYRANGE_TYPE -resourceUrl $collectionsUrl -now $now
233+
$encodedAuthString = Get-AuthorizationHeader -ResourceGroup $ResourceGroup -SubscriptionId $SubscriptionId -Database $Database -verb $GET_VERB -resourceType $PARTITIONKEYRANGE_TYPE -resourceUrl $collectionsUrl -now $now
232234

233-
$headers = Get-CommonHeaders -now $now -encodedAuthString $encodedAuthString -PartitionKey $requestPartitionKey
234-
$headers["x-ms-documentdb-query-enablecrosspartition"] = "true"
235+
$headers = Get-CommonHeaders -now $now -encodedAuthString $encodedAuthString -PartitionKey $requestPartitionKey
236+
$headers["x-ms-documentdb-query-enablecrosspartition"] = "true"
235237

236-
$response = Invoke-CosmosDbApiRequest -Verb $GET_VERB -Url $url -Headers $headers | Get-CosmosDbRecordContent
238+
$response = Invoke-CosmosDbApiRequest -Verb $GET_VERB -Url $url -Headers $headers | Get-CosmosDbRecordContent
237239

238-
$ranges = $response.partitionKeyRanges
240+
$ranges = $response.partitionKeyRanges
239241

240-
Set-CacheValue -Key $cacheKey -Value $ranges -Cache $PARTITION_KEY_RANGE_CACHE -ExpirationHours 6
242+
Set-CacheValue -Key $cacheKey -Value $ranges -Cache $PARTITION_KEY_RANGE_CACHE -ExpirationHours 6
241243

242-
$ranges
244+
$ranges
245+
}
246+
catch [System.Net.WebException]
247+
{
248+
$_.Exception
249+
}
243250
}
244251

245252
Function Get-FilteredPartitionKeyRangesForQuery($allRanges, $queryRanges)
@@ -537,10 +544,21 @@ Function Search-CosmosDbRecords(
537544
}
538545
}
539546

540-
Function Search-CosmosDbRecordsWithExtraFeatures([string]$ResourceGroup, [string]$Database, [string]$Container, [string]$Collection, [string]$Query, $Parameters, [string]$SubscriptionId)
547+
Function Search-CosmosDbRecordsWithExtraFeatures
548+
(
549+
[string]$ResourceGroup,
550+
[string]$Database,
551+
[string]$Container,
552+
[string]$Collection,
553+
[string]$Query,
554+
$Parameters,
555+
[string]$SubscriptionId
556+
)
541557
{
542558
begin
543559
{
560+
$Parameters = @(Get-QueryParametersAsNameValuePairs $Parameters)
561+
544562
$baseUrl=Get-BaseDatabaseUrl $Database
545563
$collectionsUrl=Get-CollectionsUrl $Container $Collection
546564
$docsUrl="$collectionsUrl/$DOCS_TYPE"
@@ -551,12 +569,17 @@ Function Search-CosmosDbRecordsWithExtraFeatures([string]$ResourceGroup, [string
551569

552570
$encodedAuthString=Get-AuthorizationHeader -ResourceGroup $ResourceGroup -SubscriptionId $SubscriptionId -Database $Database -verb $POST_VERB -resourceType $DOCS_TYPE -resourceUrl $collectionsUrl -now $now
553571

554-
$allPartitionKeyRanges = Get-PartitionKeyRanges -ResourceGroup $ResourceGroup -Database $Database -Container $Container -Collection $Collection -SubscriptionId $SubscriptionId
572+
$allPartitionKeyRangesOrError = Get-PartitionKeyRangesOrError -ResourceGroup $ResourceGroup -Database $Database -Container $Container -Collection $Collection -SubscriptionId $SubscriptionId
555573
}
556574
process
557575
{
558576
try
559577
{
578+
if ($allPartitionKeyRangesOrError -is [System.Net.WebException])
579+
{
580+
throw $allPartitionKeyRangesOrError
581+
}
582+
560583
$body = @{
561584
query = $Query;
562585
parameters = $Parameters;
@@ -571,32 +594,32 @@ Function Search-CosmosDbRecordsWithExtraFeatures([string]$ResourceGroup, [string
571594
"x-ms-cosmos-is-query-plan-request" = "True";
572595
}
573596

574-
$response = Invoke-CosmosDbApiRequest -verb $POST_VERB -url $url -Body $body -Headers $headers | Get-CosmosDbRecordContent
597+
$queryPlan = Invoke-CosmosDbApiRequest -verb $POST_VERB -url $url -Body $body -Headers $headers | Get-CosmosDbRecordContent
575598

576-
$rewrittenQuery = $response.QueryInfo.RewrittenQuery
599+
$rewrittenQuery = $queryPlan.QueryInfo.RewrittenQuery
577600
$searchQuery = if ($rewrittenQuery) { $rewrittenQuery } else { $Query };
578601

602+
$body = @{
603+
query = $searchQuery;
604+
parameters = $Parameters;
605+
}
606+
579607
$headers.Remove("x-ms-cosmos-is-query-plan-request")
580608

581609
$partitionKeyRanges =
582610
if ($env:COSMOS_DB_FLAG_ENABLE_PARTITION_KEY_RANGE_SEARCHES -eq 1)
583611
{
584-
Get-FilteredPartitionKeyRangesForQuery -AllRanges $partitionKeyRanges -QueryRanges $response.QueryRanges
612+
Get-FilteredPartitionKeyRangesForQuery -AllRanges $allPartitionKeyRangesOrError -QueryRanges $queryPlan.QueryRanges
585613
}
586614
else
587615
{
588-
$allPartitionKeyRanges
616+
$allPartitionKeyRangesOrError
589617
}
590618

591619
foreach ($partitionKeyRange in $partitionKeyRanges)
592620
{
593621
$headers["x-ms-documentdb-partitionkeyrangeid"] = $partitionKeyRange.id
594622

595-
$body = @{
596-
query = $searchQuery;
597-
parameters = $Parameters;
598-
}
599-
600623
Invoke-CosmosDbApiRequestWithContinuation -verb $POST_VERB -url $url -Body $body -Headers $headers
601624
}
602625
}
@@ -888,11 +911,6 @@ Function Get-CosmosDbRecordContent([parameter(ValueFromPipeline)]$RecordResponse
888911
}
889912
}
890913

891-
Function Use-CosmosDbFiddlerDebugging()
892-
{
893-
$env:AZURE_CLI_DISABLE_CONNECTION_VERIFICATION=1
894-
}
895-
896914
Function Use-CosmosDbInternalFlag
897915
(
898916
$enableFiddlerDebugging=$null,
+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
Get-Module cosmos-db | Remove-Module -Force
2+
Import-Module $PSScriptRoot\..\cosmos-db\cosmos-db.psm1 -Force
3+
4+
InModuleScope cosmos-db {
5+
Describe "Get-AllCosmosDbRecords" {
6+
BeforeAll {
7+
Use-CosmosDbInternalFlag -EnableCaching $false
8+
9+
. $PSScriptRoot\Utils.ps1
10+
11+
$global:capturedNow = $null
12+
13+
$MOCK_SUB = "MOCK_SUB"
14+
$MOCK_RG = "MOCK_RG"
15+
$MOCK_DB = "MOCK_DB"
16+
$MOCK_CONTAINER = "MOCK_CONTAINER"
17+
$MOCK_COLLECTION = "MOCK_COLLECTION"
18+
19+
$MOCK_AUTH_HEADER = "MockAuthHeader"
20+
21+
Function VerifyGetAuthHeader($ResourceGroup, $SubscriptionId, $Database, $verb, $resourceType, $resourceUrl, $now)
22+
{
23+
$ResourceGroup | Should -Be $MOCK_RG
24+
$SubscriptionId | Should -Be $MOCK_SUB
25+
26+
$verb | Should -Be "get"
27+
$resourceType | Should -Be "docs"
28+
$resourceUrl | Should -Be "dbs/$MOCK_CONTAINER/colls/$MOCK_COLLECTION"
29+
}
30+
31+
Function VerifyInvokeCosmosDbApiRequest($verb, $url, $body, $headers, $partitionKey=$MOCK_RECORD_ID)
32+
{
33+
$verb | Should -Be "get"
34+
$url | Should -Be "https://$MOCK_DB.documents.azure.com/dbs/$MOCK_CONTAINER/colls/$MOCK_COLLECTION/docs"
35+
$body | Should -Be $null
36+
37+
$global:capturedNow | Should -Not -Be $null
38+
39+
$expectedHeaders = Get-CommonHeaders -now $global:capturedNow -encodedAuthString $MOCK_AUTH_HEADER -isQuery $true
40+
41+
AssertHashtablesEqual $expectedHeaders $headers
42+
}
43+
44+
Mock Get-AuthorizationHeader {
45+
param($ResourceGroup, $SubscriptionId, $Database, $verb, $resourceType, $resourceUrl, $now)
46+
47+
VerifyGetAuthHeader $ResourceGroup $SubscriptionId $Database $verb $resourceType $resourceUrl $now | Out-Null
48+
49+
$global:capturedNow = $now
50+
51+
$MOCK_AUTH_HEADER
52+
}
53+
}
54+
55+
It "Sends correct request" {
56+
$response = @{
57+
StatusCode = 200;
58+
Content = "{}";
59+
Headers = @{};
60+
}
61+
62+
Mock Invoke-CosmosDbApiRequestWithContinuation {
63+
param($verb, $url, $body, $headers)
64+
65+
VerifyInvokeCosmosDbApiRequest $verb $url $body $headers | Out-Null
66+
67+
$response
68+
}
69+
70+
$result = Get-AllCosmosDbRecords -ResourceGroup $MOCK_RG -SubscriptionId $MOCK_SUB -Database $MOCK_DB -Container $MOCK_CONTAINER -Collection $MOCK_COLLECTION
71+
72+
$result | Should -BeExactly $response
73+
74+
Assert-MockCalled Invoke-CosmosDbApiRequestWithContinuation -Times 1
75+
}
76+
77+
It "Returns multiple responses" {
78+
$response1 = @{
79+
StatusCode = 200;
80+
Content = "1";
81+
Headers = @{};
82+
}
83+
84+
$response2 = @{
85+
StatusCode = 200;
86+
Content = "1";
87+
Headers = @{};
88+
}
89+
90+
$response3 = @{
91+
StatusCode = 200;
92+
Content = "1";
93+
Headers = @{};
94+
}
95+
96+
Mock Invoke-CosmosDbApiRequestWithContinuation {
97+
param($verb, $url, $body, $headers)
98+
99+
VerifyInvokeCosmosDbApiRequest $verb $url $body $headers | Out-Null
100+
101+
$response1
102+
$response2
103+
$response3
104+
}
105+
106+
$result = Get-AllCosmosDbRecords -ResourceGroup $MOCK_RG -SubscriptionId $MOCK_SUB -Database $MOCK_DB -Container $MOCK_CONTAINER -Collection $MOCK_COLLECTION
107+
108+
$result.Count | Should -Be 3
109+
$result[0] | Should -BeExactly $response1
110+
$result[1] | Should -BeExactly $response2
111+
$result[2] | Should -BeExactly $response3
112+
113+
Assert-MockCalled Invoke-CosmosDbApiRequestWithContinuation -Times 1
114+
}
115+
116+
It "Should handle exceptions gracefully" {
117+
$response = [System.Net.HttpWebResponse]@{}
118+
119+
Mock Invoke-CosmosDbApiRequest {
120+
param($verb, $url, $body, $headers)
121+
122+
VerifyInvokeCosmosDbApiRequest $verb $url $body $headers | Out-Null
123+
124+
throw [System.Net.WebException]::new("", $null, [System.Net.WebExceptionStatus]::UnknownError, $response)
125+
}
126+
127+
$result = Get-AllCosmosDbRecords -ResourceGroup $MOCK_RG -SubscriptionId $MOCK_SUB -Database $MOCK_DB -Container $MOCK_CONTAINER -Collection $MOCK_COLLECTION
128+
129+
$result | Should -BeExactly $response
130+
}
131+
}
132+
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Get-Module cosmos-db | Remove-Module -Force
2+
Import-Module $PSScriptRoot\..\cosmos-db\cosmos-db.psm1 -Force
3+
4+
InModuleScope cosmos-db {
5+
Describe "Get-AuthorizationHeader" {
6+
BeforeAll {
7+
Use-CosmosDbInternalFlag -EnableCaching $false
8+
9+
$MOCK_SUB = "MOCK_SUB"
10+
$MOCK_RG = "MOCK_RG"
11+
$MOCK_DB = "MOCK_DB"
12+
$MOCK_RESOURCE_URL = "MOCK_RESOURCE_URL"
13+
$MOCK_RESOURCE_TYPE = "MOCK_RESOURCE_TYPE"
14+
$MOCK_VERB = "MOCK_VERB"
15+
$MOCK_NOW = "MOCK_NOW"
16+
17+
$MOCK_MASTER_KEY_BYTES = [System.Text.Encoding]::UTF8.GetBytes('gVkYp3s6v9y$B&E)H@MbQeThWmZq4t7w')
18+
19+
Mock Get-Base64Masterkey {
20+
param($ResourceGroup, $Database, $SubscriptionId)
21+
22+
$ResourceGroup | Should -Be $MOCK_RG | Out-Null
23+
$Database | Should -Be $MOCK_DB | Out-Null
24+
$SubscriptionId | Should -Be $MOCK_SUB | Out-Null
25+
26+
[System.Convert]::ToBase64String($MOCK_MASTER_KEY_BYTES)
27+
}
28+
}
29+
30+
It "Returns the correct signature hashed with the master key" {
31+
$result = Get-AuthorizationHeader -ResourceGroup $MOCK_RG -SubscriptionId $MOCK_SUB -Database $MOCK_DB -Verb $MOCK_VERB -ResourceType $MOCK_RESOURCE_TYPE -ResourceUrl $MOCK_RESOURCE_URL -Now $MOCK_NOW
32+
33+
$expectedSignature = "$MOCK_VERB`n$MOCK_RESOURCE_TYPE`n$MOCK_RESOURCE_URL`n$MOCK_NOW`n`n".ToLower()
34+
35+
$hasher = New-Object System.Security.Cryptography.HMACSHA256 -Property @{ Key = $MOCK_MASTER_KEY_BYTES }
36+
$sigBinary=[System.Text.Encoding]::UTF8.GetBytes($expectedSignature)
37+
$hashBytes=$hasher.ComputeHash($sigBinary)
38+
$expectedBase64Hash=[System.Convert]::ToBase64String($hashBytes)
39+
40+
$expectedHeader = [uri]::EscapeDataString("type=master&ver=1.0&sig=$expectedBase64Hash")
41+
42+
$result | Should -Be $expectedHeader
43+
44+
Assert-MockCalled Get-Base64Masterkey -Times 1
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)