diff --git a/src/Groups/v1.0/test/New-MgGroup.Recording.json b/src/Groups/v1.0/test/New-MgGroup.Recording.json new file mode 100644 index 00000000000..d61bfbeaf1d --- /dev/null +++ b/src/Groups/v1.0/test/New-MgGroup.Recording.json @@ -0,0 +1,35 @@ +{ + "New-MgGroup+[NoContext]+ShouldCreateNewGroup+$POST+https://graph.microsoft.com/v1.0/groups+1": { + "Request": { + "Method": "POST", + "RequestUri": "https://graph.microsoft.com/v1.0/groups", + "Content": "{\r\n \"displayName\": \"new-mggroup-test\",\r\n \"mailEnabled\": false,\r\n \"mailNickname\": \"unused\",\r\n \"securityEnabled\": true\r\n}", + "isContentBase64": false, + "Headers": { + }, + "ContentHeaders": { + "Content-Type": [ "application/json" ], + "Content-Length": [ "123" ] + } + }, + "Response": { + "StatusCode": 200, + "Headers": { + "Transfer-Encoding": [ "chunked" ], + "Vary": [ "Accept-Encoding" ], + "Strict-Transport-Security": [ "max-age=31536000" ], + "request-id": [ "86476695-f973-44df-8964-2a53227404ab" ], + "client-request-id": [ "aeceaf2b-98af-4fc0-a276-577a2e182727" ], + "x-ms-ags-diagnostic": [ "{\"ServerInfo\":{\"DataCenter\":\"West US 2\",\"Slice\":\"E\",\"Ring\":\"1\",\"ScaleUnit\":\"001\",\"RoleInstance\":\"MW2PEPF0000749D\"}}" ], + "WWW-Authenticate": [ "Bearer realm=\"\", authorization_uri=\"https://login.microsoftonline.com/common/oauth2/authorize\", client_id=\"00000003-0000-0000-c000-000000000000\"" ], + "Date": [ "Mon, 19 Jun 2023 23:03:34 GMT" ] + }, + "ContentHeaders": { + "Content-Type": [ "application/json" ], + "Content-Encoding": [ "gzip" ] + }, + "Content": "{\r\n \"@odata.context\": \"https://graph.microsoft.com/v1.0/$metadata#groups/$entity\",\r\n \"id\": \"02bd9fd6-8f93-4758-87c3-1fb73740a315\",\r\n \"displayName\": \"new-mggroup-test\",\r\n \"groupTypes\": [\r\n \"Unified\"\r\n ],\r\n \"mailEnabled\": false,\r\n \"mailNickname\": \"unused\",\r\n \"securityEnabled\": true\r\n}", + "isContentBase64": false + } + } +} \ No newline at end of file diff --git a/src/Groups/v1.0/test/New-MgGroup.Tests.ps1 b/src/Groups/v1.0/test/New-MgGroup.Tests.ps1 new file mode 100644 index 00000000000..607f06c9cb5 --- /dev/null +++ b/src/Groups/v1.0/test/New-MgGroup.Tests.ps1 @@ -0,0 +1,38 @@ +BeforeAll { + if (($null -eq $TestName) -or ($TestName -contains 'New-MgGroup')) { + # Set test mode to playback. + $TestMode = 'playback' + $loadEnvPath = Join-Path $PSScriptRoot 'loadEnv.ps1' + if (-Not (Test-Path -Path $loadEnvPath)) { + $loadEnvPath = Join-Path $PSScriptRoot '..\loadEnv.ps1' + } + . ($loadEnvPath) + $TestRecordingFile = Join-Path $PSScriptRoot 'New-MgGroup.Recording.json' + $currentPath = $PSScriptRoot + while (-not $mockingPath) { + $mockingPath = Get-ChildItem -Path $currentPath -Recurse -Include 'HttpPipelineMocking.ps1' -File + $currentPath = Split-Path -Path $currentPath -Parent + } + . ($mockingPath | Select-Object -First 1).FullName + } +} + +Describe 'New-MgGroup' { + BeforeAll { + $Mock.PushDescription('New-MgGroup') + } + + Context 'Create' { + It 'ShouldCreateNewGroup' { + $CreateGroups = @() + 1..100 | ForEach-Object { + $Mock.PushScenario('ShouldCreateNewGroup') + $CreateGroups += New-MgGroup -DisplayName "new-mggroup-test" -MailEnabled:$false -MailNickname 'unused' -SecurityEnabled + } + + $CreateGroups | Should -HaveCount 100 + $CreateGroups[0].DisplayName | Should -Be "new-mggroup-test" + $CreateGroups[0].MailEnabled | Should -BeFalse + } + } +} diff --git a/tools/Custom/HttpMessageLogFormatter.cs b/tools/Custom/HttpMessageLogFormatter.cs index 6b1b5a4cdb3..b44c3c7da73 100644 --- a/tools/Custom/HttpMessageLogFormatter.cs +++ b/tools/Custom/HttpMessageLogFormatter.cs @@ -34,18 +34,26 @@ internal static async Task CloneAsync(this HttpRequestMessag if (originalRequest.Content != null) { // HttpClient doesn't rewind streams and we have to explicitly do so. - await originalRequest.Content.ReadAsStreamAsync().ContinueWith(t => + var ms = new MemoryStream(); + await originalRequest.Content.CopyToAsync(ms); + ms.Position = 0; + newRequest.Content = new StreamContent(ms); + // Attempt to copy request content headers with a single retry. + // HttpHeaders dictionary is not thread-safe when targeting anything below .NET 7. For more information, see https://github.com/dotnet/runtime/issues/61798. + int retryCount = 0; + int maxRetryCount = 2; + while (retryCount < maxRetryCount) { - if (t.Result.CanSeek) - t.Result.Seek(0, SeekOrigin.Begin); - - newRequest.Content = new StreamContent(t.Result); - }).ConfigureAwait(false); - - // Copy content headers. - if (originalRequest.Content.Headers != null) - foreach (var contentHeader in originalRequest.Content.Headers) - newRequest.Content.Headers.TryAddWithoutValidation(contentHeader.Key, contentHeader.Value); + try + { + originalRequest.Content.Headers?.ToList().ForEach(header => newRequest.Content.Headers.TryAddWithoutValidation(header.Key, header.Value)); + retryCount = maxRetryCount; + } + catch (InvalidOperationException) + { + retryCount++; + } + } } return newRequest; } diff --git a/tools/Tests/loadEnv.ps1 b/tools/Tests/loadEnv.ps1 index c5ed68dee1e..e9d8834c948 100644 --- a/tools/Tests/loadEnv.ps1 +++ b/tools/Tests/loadEnv.ps1 @@ -11,24 +11,12 @@ # See the License for the specific language governing permissions and # limitations under the License. # ---------------------------------------------------------------------------------- -$envFile = 'env.json' -if ($TestMode -eq 'live') { - $envFile = 'localEnv.json' -} -if (Test-Path -Path (Join-Path $PSScriptRoot $envFile)) { - $envFilePath = Join-Path $PSScriptRoot $envFile -} else { - $envFilePath = Join-Path $PSScriptRoot '..\$envFile' +if ($TestMode -eq 'live' -or $TestMode -eq 'record') { + Connect-MgGraph -ClientId $env:testApp_clientId -TenantId $env:testApp_tenantId -CertificateThumbprint $env:testApp_certThumbprint +} +else { + # Use dummy access token to run Pester tests. + # Provide the dummy access token to $env:testApp_dummyAccessToken in your environment variable. + Connect-MgGraph -AccessToken (ConvertTo-SecureString -String $env:testApp_dummyAccessToken -AsPlainText) } -$env = @{} -if (Test-Path -Path $envFilePath) { - # Load dummy auth configuration. This is used to run Pester tests. - $env = Get-Content (Join-Path $PSScriptRoot $envFile) | ConvertFrom-Json -AsHashTable - [Microsoft.Graph.PowerShell.Authentication.GraphSession]::Instance.AuthContext = New-Object Microsoft.Graph.PowerShell.Authentication.AuthContext -Property @{ - ClientId = $env.ClientId - TenantId = $env.TenantId - AuthType = [Microsoft.Graph.PowerShell.Authentication.AuthenticationType]::UserProvidedAccessToken - TokenCredentialType = [Microsoft.Graph.PowerShell.Authentication.TokenCredentialType]::UserProvidedAccessToken - } -} \ No newline at end of file