Auto-install and run standalone test proxy server per test package (#21168)
* Auto-install and run standalone test proxy server per test package * Update recording tests to use standalone proxy * Simplify proxy binary switch statement * Add test proxy auto-install docs * Fix up recording test coverage * Add StopTestProxy note about go process handling * Proxy restore/race condition handling. Force ignore PROXY_MANUAL_START in internal tests * Fix recording readme error handling
This commit is contained in:
Родитель
c83d84e92c
Коммит
4dec079c18
|
@ -53,3 +53,6 @@ vendor/
|
|||
|
||||
# Default Test Proxy Assets restore directory
|
||||
.assets
|
||||
|
||||
# Default Test Proxy tools install directory
|
||||
.proxy
|
||||
|
|
|
@ -135,7 +135,7 @@ Testing is built into the Go toolchain as well with the `testing` library. The t
|
|||
| playback | `$ENV:AZURE_RECORD_MODE="playback"` | Running tests against recording HTTP interactiosn |
|
||||
| live | `$ENV:AZURE_RECORD_MODE="live"` | Bypassing test proxy, running against live service, and not recording HTTP interactions (used by live pipelines) |
|
||||
|
||||
To get started first [install test-proxy][test_proxy_install] via the standalone executable. Then to start the proxy, from the root of the repository, run the command `test-proxy start`.
|
||||
By default the [recording](recording_package) package will automatically install and run the test proxy server. If there are issues with auto-install or the proxy needs to be run standalone, it can be run manually instead. To get started first [install test-proxy][test_proxy_install] via the standalone executable, then to start the proxy, from the root of the repository, run the command `test-proxy start`. When invoking tests, set the environment variable `PROXY_MANUAL_START` to `true`.
|
||||
|
||||
### Test Mode Options
|
||||
|
||||
|
@ -380,3 +380,4 @@ This creates the pipelines that will verify future PRs. The `azure-sdk-for-go` i
|
|||
[autorest_intro]: https://github.com/Azure/autorest/blob/main/docs/readme.md
|
||||
[autorest_directives]: https://github.com/Azure/autorest/blob/main/docs/generate/directives.md
|
||||
[test_resources]: https://github.com/Azure/azure-sdk-tools/tree/main/eng/common/TestResources
|
||||
[recording_package]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/internal/recording
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
### Features Added
|
||||
|
||||
* Add support for auto-installing the test proxy standalone tooling in the test recording package
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
### Bugs Fixed
|
||||
|
|
|
@ -4,20 +4,37 @@
|
|||
package perf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/recording"
|
||||
)
|
||||
|
||||
func TestRecordingHTTPClient_Do(t *testing.T) {
|
||||
// Ignore manual start in pipeline tests, we always want to exercise install
|
||||
os.Setenv(recording.ProxyManualStartEnv, "false")
|
||||
|
||||
proxy, err := recording.StartTestProxy("", nil)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
err := recording.StopTestProxy(proxy)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
req, err := http.NewRequest("POST", "https://www.bing.com", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
proxyURL := fmt.Sprintf("https://localhost:%d", proxy.Options.ProxyPort)
|
||||
client := NewProxyTransport(&TransportOptions{
|
||||
TestName: t.Name(),
|
||||
proxyURL: "https://localhost:5001/",
|
||||
proxyURL: proxyURL,
|
||||
})
|
||||
require.NotNil(t, client)
|
||||
|
||||
|
@ -32,7 +49,7 @@ func TestRecordingHTTPClient_Do(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
resp, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "https://localhost:5001", resp.Request.URL.String())
|
||||
require.Equal(t, proxyURL, resp.Request.URL.String())
|
||||
require.Contains(t, resp.Request.Header.Get(upstreamURIHeader), "https://www.bing.com")
|
||||
require.Equal(t, resp.Request.Header.Get(modeHeader), "record")
|
||||
require.Equal(t, resp.Request.Header.Get(idHeader), client.recID)
|
||||
|
@ -42,7 +59,7 @@ func TestRecordingHTTPClient_Do(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
resp, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "https://localhost:5001", resp.Request.URL.String())
|
||||
require.Equal(t, proxyURL, resp.Request.URL.String())
|
||||
require.Contains(t, resp.Request.Header.Get(upstreamURIHeader), "https://www.bing.com")
|
||||
require.Equal(t, resp.Request.Header.Get(modeHeader), "playback")
|
||||
require.Equal(t, resp.Request.Header.Get(idHeader), client.recID)
|
||||
|
|
|
@ -16,9 +16,33 @@ After you've set the `AZURE_RECORD_MODE`, set the `PROXY_CERT` environment varia
|
|||
$ENV:PROXY_CERT="C:/ <path-to-repo> /azure-sdk-for-go/eng/common/testproxy/dotnet-devcert.crt"
|
||||
```
|
||||
|
||||
## Running the test proxy
|
||||
|
||||
Recording and playing back tests relies on the [Test Proxy](https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/Azure.Sdk.Tools.TestProxy/README.md) to intercept traffic. The recording package can automatically install and run an instance of the test-proxy server per package. The following code needs to be added to test setup and teardown in order to achieve this:
|
||||
|
||||
```golang
|
||||
func TestMain(m *testing.M) {
|
||||
proxy, err := recording.StartTestProxy(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
... all other test code, including proxy recording setup ...
|
||||
|
||||
code := m.Run()
|
||||
|
||||
err = recording.StopTestProxy(proxy)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
os.Exit(code)
|
||||
}
|
||||
```
|
||||
|
||||
## Routing Traffic
|
||||
|
||||
The first step in instrumenting a client to interact with recorded tests is to direct traffic to the proxy through a custom `policy`. In these examples we'll use testify's [`require`](https://pkg.go.dev/github.com/stretchr/testify/require) library but you can use the framework of your choice. Each test has to call `recording.Start` and `recording.Stop`, the rest is taken care of by the `recording` library and the [`test-proxy`](https://github.com/Azure/azure-sdk-tools/tree/main/tools/test-proxy)
|
||||
The first step in instrumenting a client to interact with recorded tests is to direct traffic to the proxy through a custom `policy`. In these examples we'll use testify's [`require`](https://pkg.go.dev/github.com/stretchr/testify/require) library but you can use the framework of your choice. Each test has to call `recording.Start` and `recording.Stop`, the rest is taken care of by the `recording` library and the [`test-proxy`](https://github.com/Azure/azure-sdk-tools/tree/main/tools/test-proxy).
|
||||
|
||||
The snippet below demonstrates an example test policy:
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ package recording
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -76,7 +77,8 @@ func SetDefaultMatcher(t *testing.T, options *SetDefaultMatcherOptions) error {
|
|||
return nil
|
||||
}
|
||||
options.fillOptions()
|
||||
req, err := http.NewRequest("POST", "http://localhost:5000/Admin/SetMatcher", http.NoBody)
|
||||
url := fmt.Sprintf("%s/Admin/SetMatcher", defaultOptions().baseURL())
|
||||
req, err := http.NewRequest("POST", url, http.NoBody)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -9,167 +9,197 @@ package recording
|
|||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
func TestSetBodilessMatcher(t *testing.T) {
|
||||
temp := recordMode
|
||||
recordMode = RecordingMode
|
||||
defer func() { recordMode = temp }()
|
||||
|
||||
err := Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://bing.com")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Run a second request to with different body to verify it works
|
||||
recordMode = PlaybackMode
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = SetBodilessMatcher(t, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
req, err = http.NewRequest("POST", "https://localhost:5001", bytes.NewReader([]byte("abcdef")))
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://bing.com")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
type matchersTests struct {
|
||||
suite.Suite
|
||||
proxy *TestProxyInstance
|
||||
}
|
||||
|
||||
func TestSetBodilessMatcherNilTest(t *testing.T) {
|
||||
func TestMatchers(t *testing.T) {
|
||||
suite.Run(t, new(matchersTests))
|
||||
}
|
||||
|
||||
func (s *matchersTests) SetupSuite() {
|
||||
// Ignore manual start in pipeline tests, we always want to exercise install
|
||||
os.Setenv(ProxyManualStartEnv, "false")
|
||||
proxy, err := StartTestProxy("", nil)
|
||||
s.proxy = proxy
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *matchersTests) TearDownSuite() {
|
||||
err1 := StopTestProxy(s.proxy)
|
||||
err2 := os.RemoveAll("./testdata/recordings/TestMatchers/")
|
||||
require.NoError(s.T(), err1)
|
||||
require.NoError(s.T(), err2)
|
||||
}
|
||||
|
||||
func (s *matchersTests) TestSetBodilessMatcher() {
|
||||
require := require.New(s.T())
|
||||
temp := recordMode
|
||||
recordMode = RecordingMode
|
||||
defer func() { recordMode = temp }()
|
||||
|
||||
err := Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err := Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://bing.com")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Run a second request to with different body to verify it works
|
||||
recordMode = PlaybackMode
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
err = SetBodilessMatcher(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req, err = http.NewRequest("POST", defaultOptions().baseURL(), bytes.NewReader([]byte("abcdef")))
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://bing.com")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(err)
|
||||
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
err = ResetProxy(nil)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
func (s *matchersTests) TestSetBodilessMatcherNilTest() {
|
||||
require := require.New(s.T())
|
||||
temp := recordMode
|
||||
recordMode = RecordingMode
|
||||
defer func() { recordMode = temp }()
|
||||
|
||||
err := Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://bing.com")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(err)
|
||||
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Run a second request to with different body to verify it works
|
||||
recordMode = PlaybackMode
|
||||
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
err = SetBodilessMatcher(nil, nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
req, err = http.NewRequest("POST", "https://localhost:5001", bytes.NewReader([]byte("abcdef")))
|
||||
require.NoError(t, err)
|
||||
req, err = http.NewRequest("POST", defaultOptions().baseURL(), bytes.NewReader([]byte("abcdef")))
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://bing.com")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
err = ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
func TestSetDefaultMatcher(t *testing.T) {
|
||||
func (s *matchersTests) TestSetDefaultMatcher() {
|
||||
require := require.New(s.T())
|
||||
temp := recordMode
|
||||
recordMode = RecordingMode
|
||||
defer func() { recordMode = temp }()
|
||||
|
||||
err := Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err := Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://bing.com")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Run a second request to with different body to verify it works
|
||||
recordMode = PlaybackMode
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
err = SetDefaultMatcher(nil, &SetDefaultMatcherOptions{ExcludedHeaders: []string{"ExampleHeader"}})
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
req, err = http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err = http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://bing.com")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
req.Header.Set("ExampleHeader", "blah-blah-blah")
|
||||
|
||||
err = handleProxyResponse(client.Do(req))
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
err = ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
func TestAddDefaults(t *testing.T) {
|
||||
require.Equal(t, 4, len(addDefaults([]string{})))
|
||||
require.Equal(t, 4, len(addDefaults([]string{":path"})))
|
||||
require.Equal(t, 4, len(addDefaults([]string{":path", ":authority"})))
|
||||
require.Equal(t, 4, len(addDefaults([]string{":path", ":authority", ":method"})))
|
||||
require.Equal(t, 4, len(addDefaults([]string{":path", ":authority", ":method", ":scheme"})))
|
||||
require.Equal(t, 5, len(addDefaults([]string{":path", ":authority", ":method", ":scheme", "extra"})))
|
||||
func (s *matchersTests) TestAddDefaults() {
|
||||
require := require.New(s.T())
|
||||
require.Equal(4, len(addDefaults([]string{})))
|
||||
require.Equal(4, len(addDefaults([]string{":path"})))
|
||||
require.Equal(4, len(addDefaults([]string{":path", ":authority"})))
|
||||
require.Equal(4, len(addDefaults([]string{":path", ":authority", ":method"})))
|
||||
require.Equal(4, len(addDefaults([]string{":path", ":authority", ":method", ":scheme"})))
|
||||
require.Equal(5, len(addDefaults([]string{":path", ":authority", ":method", ":scheme", "extra"})))
|
||||
}
|
||||
|
|
|
@ -524,6 +524,7 @@ var client = http.Client{
|
|||
|
||||
type RecordingOptions struct {
|
||||
UseHTTPS bool
|
||||
ProxyPort int
|
||||
GroupForReplace string
|
||||
Variables map[string]interface{}
|
||||
TestInstance *testing.T
|
||||
|
@ -531,7 +532,8 @@ type RecordingOptions struct {
|
|||
|
||||
func defaultOptions() *RecordingOptions {
|
||||
return &RecordingOptions{
|
||||
UseHTTPS: true,
|
||||
UseHTTPS: true,
|
||||
ProxyPort: os.Getpid()%10000 + 20000,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,6 +560,10 @@ func (r RecordingOptions) ReplaceAuthority(t *testing.T, rawReq *http.Request) *
|
|||
}
|
||||
|
||||
func (r RecordingOptions) host() string {
|
||||
if r.ProxyPort != 0 {
|
||||
return fmt.Sprintf("localhost:%d", r.ProxyPort)
|
||||
}
|
||||
|
||||
if r.UseHTTPS {
|
||||
return "localhost:5001"
|
||||
}
|
||||
|
@ -589,7 +595,7 @@ func getGitRoot(fromPath string) (string, error) {
|
|||
|
||||
root, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Unable to find git root for path '%s'", absPath)
|
||||
return "", fmt.Errorf("unable to find git root for path '%s'", absPath)
|
||||
}
|
||||
|
||||
// Wrap with Abs() to get os-specific path separators to support sub-path matching
|
||||
|
@ -667,7 +673,6 @@ func requestStart(url string, testId string, assetConfigLocation string) (*http.
|
|||
return client.Do(req)
|
||||
}
|
||||
|
||||
// Start tells the test proxy to begin accepting requests for a given test
|
||||
func Start(t *testing.T, pathToRecordings string, options *RecordingOptions) error {
|
||||
if options == nil {
|
||||
options = defaultOptions()
|
||||
|
@ -789,6 +794,9 @@ func Stop(t *testing.T, options *RecordingOptions) error {
|
|||
req.Header.Set(IDHeader, recTest.recordingId)
|
||||
testSuite.Remove(t.Name())
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
|
@ -940,7 +948,7 @@ func (c RecordingHTTPClient) Do(req *http.Request) (*http.Response, error) {
|
|||
// NewRecordingHTTPClient returns a type that implements `azcore.Transporter`. This will automatically route tests on the `Do` call.
|
||||
func NewRecordingHTTPClient(t *testing.T, options *RecordingOptions) (*RecordingHTTPClient, error) {
|
||||
if options == nil {
|
||||
options = &RecordingOptions{UseHTTPS: true}
|
||||
options = defaultOptions()
|
||||
}
|
||||
c, err := GetHTTPClient(t)
|
||||
if err != nil {
|
||||
|
|
|
@ -24,14 +24,37 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
const packagePath = "sdk/internal/recording/testdata"
|
||||
|
||||
type recordingTests struct {
|
||||
suite.Suite
|
||||
proxy *TestProxyInstance
|
||||
}
|
||||
|
||||
func TestRecording(t *testing.T) {
|
||||
suite.Run(t, new(recordingTests))
|
||||
}
|
||||
|
||||
func (s *recordingTests) SetupSuite() {
|
||||
// Ignore manual start in pipeline tests, we always want to exercise install
|
||||
os.Setenv(ProxyManualStartEnv, "false")
|
||||
proxy, err := StartTestProxy("", nil)
|
||||
s.proxy = proxy
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *recordingTests) TearDownSuite() {
|
||||
stopErr := StopTestProxy(s.proxy)
|
||||
require.NoError(s.T(), stopErr)
|
||||
|
||||
files, err := filepath.Glob("recordings/**/*.yaml")
|
||||
require.NoError(s.T(), err)
|
||||
for _, f := range files {
|
||||
err := os.Remove(f)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *recordingTests) TestInitializeRecording() {
|
||||
require := require.New(s.T())
|
||||
context := NewTestContext(func(msg string) { require.FailNow(msg) }, func(msg string) { s.T().Log(msg) }, func() string { return s.T().Name() })
|
||||
|
@ -239,7 +262,7 @@ func (s *recordingTests) TestNow() {
|
|||
require.NoError(err)
|
||||
}
|
||||
|
||||
func (s *recordingTests) TestGenerateAlphaNumericID() {
|
||||
func (s *recordingTests) TestRecordingGenerateAlphaNumericID() {
|
||||
require := require.New(s.T())
|
||||
context := NewTestContext(func(msg string) { require.FailNow(msg) }, func(msg string) { s.T().Log(msg) }, func() string { return s.T().Name() })
|
||||
|
||||
|
@ -370,215 +393,214 @@ func (s *recordingTests) TestRecordRequestsAndFailMatchingForMissingRecording()
|
|||
require.NoError(err)
|
||||
}
|
||||
|
||||
func (s *recordingTests) TearDownSuite() {
|
||||
files, err := filepath.Glob("recordings/**/*.yaml")
|
||||
require.NoError(s.T(), err)
|
||||
for _, f := range files {
|
||||
err := os.Remove(f)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEnvVariable(t *testing.T) {
|
||||
require.Equal(t, GetEnvVariable("Nonexistentevnvar", "somefakevalue"), "somefakevalue")
|
||||
func (s *recordingTests) TestGetEnvVariable() {
|
||||
require := require.New(s.T())
|
||||
require.Equal(GetEnvVariable("Nonexistentevnvar", "somefakevalue"), "somefakevalue")
|
||||
temp := recordMode
|
||||
recordMode = RecordingMode
|
||||
t.Setenv("TEST_VARIABLE", "expected")
|
||||
require.Equal(t, "expected", GetEnvVariable("TEST_VARIABLE", "unexpected"))
|
||||
s.T().Setenv("TEST_VARIABLE", "expected")
|
||||
require.Equal("expected", GetEnvVariable("TEST_VARIABLE", "unexpected"))
|
||||
recordMode = temp
|
||||
}
|
||||
|
||||
func TestRecordingOptions(t *testing.T) {
|
||||
func (s *recordingTests) TestRecordingOptions() {
|
||||
require := require.New(s.T())
|
||||
r := RecordingOptions{
|
||||
UseHTTPS: true,
|
||||
}
|
||||
require.Equal(t, r.baseURL(), "https://localhost:5001")
|
||||
require.Equal(r.baseURL(), "https://localhost:5001")
|
||||
|
||||
r.UseHTTPS = false
|
||||
require.Equal(t, r.baseURL(), "http://localhost:5000")
|
||||
require.Equal(r.baseURL(), "http://localhost:5000")
|
||||
|
||||
r = *defaultOptions()
|
||||
require.Equal(r.baseURL(), fmt.Sprintf("https://localhost:%d", r.ProxyPort))
|
||||
// ProxyPort should be generated deterministically
|
||||
require.Equal(r.ProxyPort, defaultOptions().ProxyPort)
|
||||
}
|
||||
|
||||
var packagePath = "sdk/internal/recording/testdata"
|
||||
|
||||
func TestStartStop(t *testing.T) {
|
||||
func (s *recordingTests) TestStartStop() {
|
||||
require := require.New(s.T())
|
||||
os.Setenv("AZURE_RECORD_MODE", "record")
|
||||
defer os.Unsetenv("AZURE_RECORD_MODE")
|
||||
|
||||
err := Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err := Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://www.bing.com/")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open("./testdata/recordings/TestStartStop.json")
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
}
|
||||
|
||||
func TestStartStopRecordingClient(t *testing.T) {
|
||||
func (s *recordingTests) TestStartStopRecordingClient() {
|
||||
require := require.New(s.T())
|
||||
temp := recordMode
|
||||
recordMode = RecordingMode
|
||||
defer func() { recordMode = temp }()
|
||||
|
||||
err := Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err := Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := NewRecordingHTTPClient(t, nil)
|
||||
require.NoError(t, err)
|
||||
client, err := NewRecordingHTTPClient(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://azsdkengsys.azurecr.io/acr/v1/some_registry/_tags", nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer func() {
|
||||
err = jsonFile.Close()
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = os.Remove(jsonFile.Name())
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
}()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "https://azsdkengsys.azurecr.io/acr/v1/some_registry/_tags", data.Entries[0].RequestURI)
|
||||
require.Equal(t, resp.Request.URL.String(), "https://localhost:5001/acr/v1/some_registry/_tags")
|
||||
require.NoError(err)
|
||||
require.Equal("https://azsdkengsys.azurecr.io/acr/v1/some_registry/_tags",
|
||||
data.Entries[0].RequestURI)
|
||||
require.Equal(resp.Request.URL.String(),
|
||||
fmt.Sprintf("%s/acr/v1/some_registry/_tags", defaultOptions().baseURL()))
|
||||
}
|
||||
|
||||
func TestStopRecordingNoStart(t *testing.T) {
|
||||
func (s *recordingTests) TestStopRecordingNoStart() {
|
||||
require := require.New(s.T())
|
||||
os.Setenv("AZURE_RECORD_MODE", "record")
|
||||
defer os.Unsetenv("AZURE_RECORD_MODE")
|
||||
|
||||
err := Stop(t, nil)
|
||||
require.Error(t, err)
|
||||
err := Stop(s.T(), nil)
|
||||
require.Error(err)
|
||||
|
||||
jsonFile, err := os.Open("./testdata/recordings/TestStopRecordingNoStart.json")
|
||||
require.Error(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.Error(err)
|
||||
defer jsonFile.Close()
|
||||
}
|
||||
|
||||
func TestLiveModeOnly(t *testing.T) {
|
||||
LiveOnly(t)
|
||||
func (s *recordingTests) TestLiveModeOnly() {
|
||||
LiveOnly(s.T())
|
||||
if GetRecordMode() == PlaybackMode {
|
||||
t.Fatalf("Test should not run in playback")
|
||||
s.T().Fatalf("Test should not run in playback")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSleep(t *testing.T) {
|
||||
func (s *recordingTests) TestSleep() {
|
||||
start := time.Now()
|
||||
Sleep(time.Second * 5)
|
||||
Sleep(time.Millisecond * 100)
|
||||
duration := time.Since(start)
|
||||
if GetRecordMode() == PlaybackMode {
|
||||
if duration > (time.Second * 1) {
|
||||
t.Fatalf("Sleep took longer than five seconds")
|
||||
if duration >= (time.Millisecond * 50) {
|
||||
s.T().Fatalf("Sleep took at least 50ms")
|
||||
}
|
||||
} else {
|
||||
if duration < (time.Second * 1) {
|
||||
t.Fatalf("Sleep took less than five seconds")
|
||||
if duration < (time.Second * 50) {
|
||||
s.T().Fatalf("Sleep took less than 50ms")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadAzureRecordMode(t *testing.T) {
|
||||
func (s *recordingTests) TestBadAzureRecordMode() {
|
||||
require := require.New(s.T())
|
||||
temp := recordMode
|
||||
|
||||
recordMode = "badvalue"
|
||||
err := Start(t, packagePath, nil)
|
||||
require.Error(t, err)
|
||||
err := Start(s.T(), packagePath, nil)
|
||||
require.Error(err)
|
||||
|
||||
recordMode = temp
|
||||
}
|
||||
|
||||
func TestBackwardSlashPath(t *testing.T) {
|
||||
t.Skip("Temporarily skipping due to changes in test-proxy.")
|
||||
func (s *recordingTests) TestBackwardSlashPath() {
|
||||
s.T().Skip("Temporarily skipping due to changes in test-proxy.")
|
||||
|
||||
require := require.New(s.T())
|
||||
os.Setenv("AZURE_RECORD_MODE", "record")
|
||||
defer os.Unsetenv("AZURE_RECORD_MODE")
|
||||
|
||||
packagePathBackslash := "sdk\\internal\\recording\\testdata"
|
||||
|
||||
err := Start(t, packagePathBackslash, nil)
|
||||
require.NoError(t, err)
|
||||
err := Start(s.T(), packagePathBackslash, nil)
|
||||
require.NoError(err)
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
func TestLiveOnly(t *testing.T) {
|
||||
require.Equal(t, IsLiveOnly(t), false)
|
||||
LiveOnly(t)
|
||||
require.Equal(t, IsLiveOnly(t), true)
|
||||
func (s *recordingTests) TestLiveOnly() {
|
||||
require := require.New(s.T())
|
||||
require.Equal(IsLiveOnly(s.T()), false)
|
||||
LiveOnly(s.T())
|
||||
require.Equal(IsLiveOnly(s.T()), true)
|
||||
}
|
||||
|
||||
func TestHostAndScheme(t *testing.T) {
|
||||
r := RecordingOptions{UseHTTPS: true}
|
||||
require.Equal(t, r.scheme(), "https")
|
||||
require.Equal(t, r.host(), "localhost:5001")
|
||||
|
||||
r.UseHTTPS = false
|
||||
require.Equal(t, r.scheme(), "http")
|
||||
require.Equal(t, r.host(), "localhost:5000")
|
||||
}
|
||||
|
||||
func TestGitRootDetection(t *testing.T) {
|
||||
func (s *recordingTests) TestGitRootDetection() {
|
||||
require := require.New(s.T())
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
gitRoot, err := getGitRoot(cwd)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
parentDir := filepath.Dir(gitRoot)
|
||||
_, err = getGitRoot(parentDir)
|
||||
require.Error(t, err)
|
||||
require.Error(err)
|
||||
}
|
||||
|
||||
func TestRecordingAssetConfigNotExist(t *testing.T) {
|
||||
func (s *recordingTests) TestRecordingAssetConfigNotExist() {
|
||||
require := require.New(s.T())
|
||||
absPath, relPath, err := getAssetsConfigLocation(".")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "", absPath)
|
||||
require.Equal(t, "", relPath)
|
||||
require.NoError(err)
|
||||
require.Equal("", absPath)
|
||||
require.Equal("", relPath)
|
||||
}
|
||||
|
||||
func TestRecordingAssetConfigOutOfBounds(t *testing.T) {
|
||||
func (s *recordingTests) TestRecordingAssetConfigOutOfBounds() {
|
||||
require := require.New(s.T())
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
gitRoot, err := getGitRoot(cwd)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
parentDir := filepath.Dir(gitRoot)
|
||||
|
||||
absPath, err := findAssetsConfigFile(parentDir, gitRoot)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "", absPath)
|
||||
require.NoError(err)
|
||||
require.Equal("", absPath)
|
||||
}
|
||||
|
||||
func TestRecordingAssetConfig(t *testing.T) {
|
||||
func (s *recordingTests) TestRecordingAssetConfig() {
|
||||
require := require.New(s.T())
|
||||
cases := []struct{ expectedDirectory, searchDirectory, testFileLocation string }{
|
||||
{"sdk/internal/recording", "sdk/internal/recording", recordingAssetConfigName},
|
||||
{"sdk/internal/recording", "sdk/internal/recording/", recordingAssetConfigName},
|
||||
|
@ -587,31 +609,32 @@ func TestRecordingAssetConfig(t *testing.T) {
|
|||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
gitRoot, err := getGitRoot(cwd)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
for _, c := range cases {
|
||||
_ = os.Remove(c.testFileLocation)
|
||||
o, err := os.Create(c.testFileLocation)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
o.Close()
|
||||
|
||||
absPath, relPath, err := getAssetsConfigLocation(c.searchDirectory)
|
||||
// Clean up first in case of an assertion panic
|
||||
require.NoError(t, os.Remove(c.testFileLocation))
|
||||
require.NoError(t, err)
|
||||
require.NoError(os.Remove(c.testFileLocation))
|
||||
require.NoError(err)
|
||||
|
||||
expected := c.expectedDirectory + string(os.PathSeparator) + recordingAssetConfigName
|
||||
expected = strings.ReplaceAll(expected, "/", string(os.PathSeparator))
|
||||
require.Equal(t, expected, relPath)
|
||||
require.Equal(expected, relPath)
|
||||
|
||||
absPathExpected := filepath.Join(gitRoot, expected)
|
||||
require.Equal(t, absPathExpected, absPath)
|
||||
require.Equal(absPathExpected, absPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindProxyCertLocation(t *testing.T) {
|
||||
func (s *recordingTests) TestFindProxyCertLocation() {
|
||||
require := require.New(s.T())
|
||||
savedValue, ok := os.LookupEnv("PROXY_CERT")
|
||||
if ok {
|
||||
defer os.Setenv("PROXY_CERT", savedValue)
|
||||
|
@ -619,120 +642,126 @@ func TestFindProxyCertLocation(t *testing.T) {
|
|||
|
||||
if ok {
|
||||
location, err := findProxyCertLocation()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, location, "dotnet-devcert.crt")
|
||||
require.NoError(err)
|
||||
require.Contains(location, "dotnet-devcert.crt")
|
||||
}
|
||||
|
||||
err := os.Unsetenv("PROXY_CERT")
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
location, err := findProxyCertLocation()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, location, filepath.Join("eng", "common", "testproxy", "dotnet-devcert.crt"))
|
||||
require.NoError(err)
|
||||
require.Contains(location, filepath.Join("eng", "common", "testproxy", "dotnet-devcert.crt"))
|
||||
}
|
||||
|
||||
func TestVariables(t *testing.T) {
|
||||
func (s *recordingTests) TestVariables() {
|
||||
require := require.New(s.T())
|
||||
temp := recordMode
|
||||
recordMode = RecordingMode
|
||||
defer func() { recordMode = temp }()
|
||||
|
||||
err := Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err := Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := NewRecordingHTTPClient(t, nil)
|
||||
require.NoError(t, err)
|
||||
client, err := NewRecordingHTTPClient(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://azsdkengsys.azurecr.io/acr/v1/some_registry/_tags", nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, &RecordingOptions{Variables: map[string]interface{}{"key1": "value1", "key2": "1"}})
|
||||
require.NoError(t, err)
|
||||
opts := defaultOptions()
|
||||
opts.Variables = map[string]interface{}{"key1": "value1", "key2": "1"}
|
||||
err = Stop(s.T(), opts)
|
||||
require.NoError(err)
|
||||
|
||||
recordMode = PlaybackMode
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
variables := GetVariables(t)
|
||||
require.Equal(t, variables["key1"], "value1")
|
||||
require.Equal(t, variables["key2"], "1")
|
||||
variables := GetVariables(s.T())
|
||||
require.Equal(variables["key1"], "value1")
|
||||
require.Equal(variables["key2"], "1")
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer func() {
|
||||
err = jsonFile.Close()
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = os.Remove(jsonFile.Name())
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
}()
|
||||
}
|
||||
|
||||
func TestRace(t *testing.T) {
|
||||
func (s *recordingTests) TestRace() {
|
||||
require := require.New(s.T())
|
||||
temp := recordMode
|
||||
recordMode = LiveMode
|
||||
t.Cleanup(func() { recordMode = temp })
|
||||
s.T().Cleanup(func() { recordMode = temp })
|
||||
for i := 0; i < 4; i++ {
|
||||
t.Run("", func(t *testing.T) {
|
||||
s.T().Run("", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := Start(t, "", nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
GetRecordingId(t)
|
||||
GetVariables(t)
|
||||
IsLiveOnly(t)
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
LiveOnly(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_generateAlphaNumericID(t *testing.T) {
|
||||
func (s *recordingTests) TestInnerGenerateAlphaNumericID() {
|
||||
require := require.New(s.T())
|
||||
seed1 := int64(1234567)
|
||||
seed2 := int64(7654321)
|
||||
randomSource1 := rand.NewSource(seed1)
|
||||
randomSource2 := rand.NewSource(seed2)
|
||||
randomSource3 := rand.NewSource(seed2)
|
||||
rand1, err := generateAlphaNumericID("test", 10, false, randomSource1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 10, len(rand1))
|
||||
require.Equal(t, "test", rand1[0:4])
|
||||
require.NoError(err)
|
||||
require.Equal(10, len(rand1))
|
||||
require.Equal("test", rand1[0:4])
|
||||
rand2, err := generateAlphaNumericID("test", 10, false, randomSource2)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
rand3, err := generateAlphaNumericID("test", 10, false, randomSource3)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, rand2, rand3)
|
||||
require.NotEqual(t, rand1, rand2)
|
||||
require.NoError(err)
|
||||
require.Equal(rand2, rand3)
|
||||
require.NotEqual(rand1, rand2)
|
||||
}
|
||||
|
||||
func TestGenerateAlphaNumericID(t *testing.T) {
|
||||
func (s *recordingTests) TestGenerateAlphaNumericID() {
|
||||
require := require.New(s.T())
|
||||
recordMode = RecordingMode
|
||||
err := Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
rand1, err := GenerateAlphaNumericID(t, "test", 10, false)
|
||||
require.NoError(t, err)
|
||||
rand2, err := GenerateAlphaNumericID(t, "test", 10, false)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, rand1, rand2)
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err := Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
rand1, err := GenerateAlphaNumericID(s.T(), "test", 10, false)
|
||||
require.NoError(err)
|
||||
rand2, err := GenerateAlphaNumericID(s.T(), "test", 10, false)
|
||||
require.NoError(err)
|
||||
require.NotEqual(rand1, rand2)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
recordMode = PlaybackMode
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
rand3, err := GenerateAlphaNumericID(t, "test", 10, false)
|
||||
require.NoError(t, err)
|
||||
rand4, err := GenerateAlphaNumericID(t, "test", 10, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, rand1, rand3)
|
||||
require.Equal(t, rand2, rand4)
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
rand3, err := GenerateAlphaNumericID(s.T(), "test", 10, false)
|
||||
require.NoError(err)
|
||||
rand4, err := GenerateAlphaNumericID(s.T(), "test", 10, false)
|
||||
require.NoError(err)
|
||||
require.Equal(rand1, rand3)
|
||||
require.Equal(rand2, rand4)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
type sanitizerTests struct {
|
||||
suite.Suite
|
||||
proxy *TestProxyInstance
|
||||
}
|
||||
|
||||
const authHeader string = "Authorization"
|
||||
|
@ -36,6 +37,19 @@ func TestRecordingSanitizer(t *testing.T) {
|
|||
suite.Run(t, new(sanitizerTests))
|
||||
}
|
||||
|
||||
func (s *sanitizerTests) SetupSuite() {
|
||||
proxy, err := StartTestProxy("", nil)
|
||||
s.proxy = proxy
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *sanitizerTests) TearDownSuite() {
|
||||
err1 := StopTestProxy(s.proxy)
|
||||
err2 := os.RemoveAll("testfiles")
|
||||
require.NoError(s.T(), err1)
|
||||
require.NoError(s.T(), err2)
|
||||
}
|
||||
|
||||
func (s *sanitizerTests) TestDefaultSanitizerSanitizesAuthHeader() {
|
||||
require := require.New(s.T())
|
||||
server, cleanup := mock.NewServer()
|
||||
|
@ -140,13 +154,6 @@ func (s *sanitizerTests) TestAddUrlSanitizerSanitizes() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *sanitizerTests) TearDownSuite() {
|
||||
require := require.New(s.T())
|
||||
// cleanup test files
|
||||
err := os.RemoveAll("testfiles")
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
func getTestFileName(t *testing.T, addSuffix bool) string {
|
||||
name := "testfiles/" + t.Name()
|
||||
if addSuffix {
|
||||
|
@ -191,552 +198,572 @@ func (e Entry) ResponseBodyByValue(k string) interface{} {
|
|||
return m[k]
|
||||
}
|
||||
|
||||
func TestUriSanitizer(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestUriSanitizer() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/"
|
||||
|
||||
err = AddURISanitizer("https://replacement.com/", srvURL, nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.Equal(t, data.Entries[0].RequestURI, "https://replacement.com/")
|
||||
require.Equal(data.Entries[0].RequestURI, "https://replacement.com/")
|
||||
}
|
||||
|
||||
func TestHeaderRegexSanitizer(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestHeaderRegexSanitizer() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/uri-sanitizer"
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
req.Header.Set("testproxy-header", "fakevalue")
|
||||
req.Header.Set("FakeStorageLocation", "https://fakeaccount.blob.core.windows.net")
|
||||
req.Header.Set("ComplexRegex", "https://fakeaccount.table.core.windows.net")
|
||||
|
||||
err = AddHeaderRegexSanitizer("testproxy-header", "Sanitized", "", nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = AddHeaderRegexSanitizer("FakeStorageLocation", "Sanitized", "https\\:\\/\\/(?<account>[a-z]+)\\.blob\\.core\\.windows\\.net", nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
// This is the only failing one
|
||||
err = AddHeaderRegexSanitizer("ComplexRegex", "Sanitized", "https\\:\\/\\/(?<account>[a-z]+)\\.(?:table|blob|queue)\\.core\\.windows\\.net", &RecordingOptions{GroupForReplace: "account"})
|
||||
require.NoError(t, err)
|
||||
opts := defaultOptions()
|
||||
opts.GroupForReplace = "account"
|
||||
err = AddHeaderRegexSanitizer("ComplexRegex", "Sanitized", "https\\:\\/\\/(?<account>[a-z]+)\\.(?:table|blob|queue)\\.core\\.windows\\.net", opts)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.Equal(t, "Sanitized", data.Entries[0].RequestHeaders["testproxy-header"])
|
||||
require.Equal(t, "Sanitized", data.Entries[0].RequestHeaders["fakestoragelocation"])
|
||||
require.Equal(t, "https://Sanitized.table.core.windows.net", data.Entries[0].RequestHeaders["complexregex"])
|
||||
require.Equal("Sanitized", data.Entries[0].RequestHeaders["testproxy-header"])
|
||||
require.Equal("Sanitized", data.Entries[0].RequestHeaders["fakestoragelocation"])
|
||||
require.Equal("https://Sanitized.table.core.windows.net", data.Entries[0].RequestHeaders["complexregex"])
|
||||
}
|
||||
|
||||
func TestBodyKeySanitizer(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestBodyKeySanitizer() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/uri-sanitizer"
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
bodyValue := map[string]string{
|
||||
"key1": "value1",
|
||||
}
|
||||
marshalled, err := json.Marshal(bodyValue)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
req.Body = io.NopCloser(bytes.NewReader(marshalled))
|
||||
|
||||
err = AddBodyKeySanitizer("$.Tag", "Sanitized", "", nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.Equal(t, "Sanitized", data.Entries[0].ResponseBodyByValue("Tag"))
|
||||
require.Equal("Sanitized", data.Entries[0].ResponseBodyByValue("Tag"))
|
||||
}
|
||||
|
||||
func TestBodyRegexSanitizer(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestBodyRegexSanitizer() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/uri-sanitizer"
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
bodyValue := map[string]string{
|
||||
"key1": "value1",
|
||||
}
|
||||
marshalled, err := json.Marshal(bodyValue)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
req.Body = io.NopCloser(bytes.NewReader(marshalled))
|
||||
|
||||
err = AddBodyRegexSanitizer("Sanitized", "Value", nil)
|
||||
require.NoError(t, err)
|
||||
err = AddBodyRegexSanitizer("Sanitized", "https\\:\\/\\/(?<account>[a-z]+)\\.(?:table|blob|queue)\\.core\\.windows\\.net", &RecordingOptions{GroupForReplace: "account"})
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
opts := defaultOptions()
|
||||
opts.GroupForReplace = "account"
|
||||
err = AddBodyRegexSanitizer("Sanitized", "https\\:\\/\\/(?<account>[a-z]+)\\.(?:table|blob|queue)\\.core\\.windows\\.net", opts)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.NotContains(t, "storageaccount", data.Entries[0].ResponseBody)
|
||||
require.NotContains(t, "Value", data.Entries[0].ResponseBody)
|
||||
require.NotContains("storageaccount", data.Entries[0].ResponseBody)
|
||||
require.NotContains("Value", data.Entries[0].ResponseBody)
|
||||
}
|
||||
|
||||
func TestRemoveHeaderSanitizer(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestRemoveHeaderSanitizer() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/uri-sanitizer"
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
req.Header.Set("FakeStorageLocation", "https://fakeaccount.blob.core.windows.net")
|
||||
req.Header.Set("ComplexRegexRemove", "https://fakeaccount.table.core.windows.net")
|
||||
|
||||
err = AddRemoveHeaderSanitizer([]string{"ComplexRegexRemove", "FakeStorageLocation"}, nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.NotContains(t, []string{"ComplexRegexRemove", "FakeStorageLocation"}, data.Entries[0].ResponseHeaders)
|
||||
require.NotContains([]string{"ComplexRegexRemove", "FakeStorageLocation"}, data.Entries[0].ResponseHeaders)
|
||||
}
|
||||
|
||||
func TestContinuationSanitizer(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestContinuationSanitizer() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/uri-sanitizer"
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
req.Header.Set("Location", "/posts/2")
|
||||
|
||||
bodyValue := map[string]string{
|
||||
"key1": "value1",
|
||||
}
|
||||
marshalled, err := json.Marshal(bodyValue)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
req.Body = io.NopCloser(bytes.NewReader(marshalled))
|
||||
|
||||
err = AddContinuationSanitizer("Location", "Sanitized", true, nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
req, err = http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err = http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
req.Header.Set("Location", "/posts/3")
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.NotContains(t, "Location", data.Entries[0].ResponseHeaders)
|
||||
require.NotContains(t, "Location", data.Entries[0].ResponseHeaders)
|
||||
require.NotContains("Location", data.Entries[0].ResponseHeaders)
|
||||
require.NotContains("Location", data.Entries[0].ResponseHeaders)
|
||||
}
|
||||
|
||||
func TestGeneralRegexSanitizer(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestGeneralRegexSanitizer() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/uri-sanitizer"
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
err = AddGeneralRegexSanitizer("Sanitized", "Value", nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.NotContains(t, "Value", data.Entries[0].ResponseBody)
|
||||
require.NotContains("Value", data.Entries[0].ResponseBody)
|
||||
}
|
||||
|
||||
func TestOAuthResponseSanitizer(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestOAuthResponseSanitizer() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/uri-sanitizer"
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
err = AddOAuthResponseSanitizer(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
func TestUriSubscriptionIdSanitizer(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestUriSubscriptionIdSanitizer() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, "https://management.azure.com/subscriptions/12345678-1234-1234-5678-123456789010/providers/Microsoft.ContainerRegistry/checkNameAvailability?api-version=2019-05-01")
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
|
||||
err = AddURISubscriptionIDSanitizer("", nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.Equal(t, "https://management.azure.com/", data.Entries[0].RequestURI)
|
||||
require.Equal("https://management.azure.com/", data.Entries[0].RequestURI)
|
||||
}
|
||||
|
||||
func TestResetSanitizers(t *testing.T) {
|
||||
defer reset(t)
|
||||
func (s *sanitizerTests) TestResetSanitizers() {
|
||||
require := require.New(s.T())
|
||||
defer reset(s.T())
|
||||
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
err = Start(s.T(), packagePath, nil)
|
||||
require.NoError(err)
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/uri-sanitizer"
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
client, err := GetHTTPClient(s.T())
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
req.Header.Set(IDHeader, GetRecordingId(t))
|
||||
req.Header.Set(IDHeader, GetRecordingId(s.T()))
|
||||
req.Header.Set("FakeStorageLocation", "https://fakeaccount.blob.core.windows.net")
|
||||
|
||||
opts := defaultOptions()
|
||||
opts.TestInstance = s.T()
|
||||
|
||||
// Add a sanitizer
|
||||
err = AddRemoveHeaderSanitizer([]string{"FakeStorageLocation"}, &RecordingOptions{TestInstance: t})
|
||||
require.NoError(t, err)
|
||||
err = AddRemoveHeaderSanitizer([]string{"FakeStorageLocation"}, opts)
|
||||
require.NoError(err)
|
||||
|
||||
// Remove all sanitizers
|
||||
err = ResetProxy(&RecordingOptions{TestInstance: t})
|
||||
require.NoError(t, err)
|
||||
err = ResetProxy(opts)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NoError(err)
|
||||
require.NotNil(resp)
|
||||
|
||||
require.NotNil(t, GetRecordingId(t))
|
||||
require.NotNil(GetRecordingId(s.T()))
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
err = Stop(s.T(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
// Make sure the file is there
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", s.T().Name()))
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
require.Equal(t, data.Entries[0].RequestHeaders["fakestoragelocation"], "https://fakeaccount.blob.core.windows.net")
|
||||
require.Equal(data.Entries[0].RequestHeaders["fakestoragelocation"], "https://fakeaccount.blob.core.windows.net")
|
||||
}
|
||||
|
||||
func TestSingleTestSanitizer(t *testing.T) {
|
||||
func (s *sanitizerTests) TestSingleTestSanitizer() {
|
||||
require := require.New(s.T())
|
||||
err := ResetProxy(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
// The first iteration, add a sanitizer for just that test. The
|
||||
// second iteration, verify that the sanitizer was not applied.
|
||||
for i := 0; i < 2; i++ {
|
||||
t.Run(fmt.Sprintf("%s-%d", t.Name(), i), func(t *testing.T) {
|
||||
s.T().Run(fmt.Sprintf("%s-%d", s.T().Name(), i), func(t *testing.T) {
|
||||
err = Start(t, packagePath, nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
if i == 0 {
|
||||
// The first time we'll set a per-test sanitizer
|
||||
// Add a sanitizer
|
||||
err = AddRemoveHeaderSanitizer([]string{"FakeStorageLocation"}, &RecordingOptions{TestInstance: t})
|
||||
require.NoError(t, err)
|
||||
opts := defaultOptions()
|
||||
opts.TestInstance = t
|
||||
err = AddRemoveHeaderSanitizer([]string{"FakeStorageLocation"}, opts)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
srvURL := "http://host.docker.internal:8080/uri-sanitizer"
|
||||
|
||||
client, err := GetHTTPClient(t)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
req, err := http.NewRequest("POST", "https://localhost:5001", nil)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest("POST", defaultOptions().baseURL(), nil)
|
||||
require.NoError(err)
|
||||
|
||||
req.Header.Set(UpstreamURIHeader, srvURL)
|
||||
req.Header.Set(ModeHeader, GetRecordMode())
|
||||
|
@ -744,26 +771,26 @@ func TestSingleTestSanitizer(t *testing.T) {
|
|||
req.Header.Set("FakeStorageLocation", "https://fakeaccount.blob.core.windows.net")
|
||||
|
||||
_, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
err = Stop(t, nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
// Read the file
|
||||
jsonFile, err := os.Open(fmt.Sprintf("./testdata/recordings/%s.json", t.Name()))
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
defer jsonFile.Close()
|
||||
|
||||
var data RecordingFileStruct
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
err = json.Unmarshal(byteValue, &data)
|
||||
require.NoError(t, err)
|
||||
require.NoError(err)
|
||||
|
||||
if i == 0 {
|
||||
require.NotContains(t, data.Entries[0].RequestHeaders, "fakestoragelocation")
|
||||
require.NotContains(data.Entries[0].RequestHeaders, "fakestoragelocation")
|
||||
} else {
|
||||
require.Equal(t, data.Entries[0].RequestHeaders["fakestoragelocation"], "https://fakeaccount.blob.core.windows.net")
|
||||
require.Equal(data.Entries[0].RequestHeaders["fakestoragelocation"], "https://fakeaccount.blob.core.windows.net")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,446 @@
|
|||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package recording
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const ProxyManualStartEnv = "PROXY_MANUAL_START"
|
||||
|
||||
type TestProxyInstance struct {
|
||||
Cmd *exec.Cmd
|
||||
Options *RecordingOptions
|
||||
}
|
||||
|
||||
func getTestProxyDownloadFile() (string, error) {
|
||||
switch {
|
||||
case runtime.GOOS == "windows":
|
||||
// No ARM binaries for Windows, so return x64
|
||||
return "test-proxy-standalone-win-x64.zip", nil
|
||||
case runtime.GOOS == "linux" && runtime.GOARCH == "amd64":
|
||||
return "test-proxy-standalone-linux-x64.tar.gz", nil
|
||||
case runtime.GOOS == "linux" && runtime.GOARCH == "arm64":
|
||||
return "test-proxy-standalone-linux-arm64.tar.gz", nil
|
||||
case runtime.GOOS == "darwin" && runtime.GOARCH == "amd64":
|
||||
return "test-proxy-standalone-osx-x64.zip", nil
|
||||
case runtime.GOOS == "darwin" && runtime.GOARCH == "arm64":
|
||||
return "test-proxy-standalone-osx-arm64.zip", nil
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported OS/Arch combination: %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
|
||||
// Modified from https://stackoverflow.com/a/24792688
|
||||
func extractTestProxyZip(src string, dest string) error {
|
||||
r, err := zip.OpenReader(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := r.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := os.MkdirAll(dest, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Closure to address file descriptors issue with all the deferred .Close() methods
|
||||
extractAndWriteFile := func(f *zip.File) error {
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := rc.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
path := filepath.Join(dest, f.Name)
|
||||
log.Println("Extracting", path)
|
||||
|
||||
// Check for ZipSlip (Directory traversal)
|
||||
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("illegal file path: %s", path)
|
||||
}
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
if err := os.MkdirAll(path, f.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := os.MkdirAll(filepath.Dir(path), f.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
_, err = io.Copy(f, rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, f := range r.File {
|
||||
err := extractAndWriteFile(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractTestProxyArchive(archivePath string, outputDir string) error {
|
||||
log.Printf("Extracting %s\n", archivePath)
|
||||
file, err := os.Open(archivePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
gzipReader, err := gzip.NewReader(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gzipReader.Close()
|
||||
|
||||
tarReader := tar.NewReader(gzipReader)
|
||||
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
targetPath := filepath.Join(outputDir, header.Name)
|
||||
|
||||
log.Println("Extracting", targetPath)
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.MkdirAll(targetPath, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
case tar.TypeReg:
|
||||
file, err := os.Create(targetPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err := io.Copy(file, tarReader); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
log.Printf("Unable to extract type %c in file %s\n", header.Typeflag, header.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func installTestProxy(archivePath string, outputDir string, proxyPath string) error {
|
||||
var err error
|
||||
if strings.HasSuffix(archivePath, ".zip") {
|
||||
err = extractTestProxyZip(archivePath, outputDir)
|
||||
} else {
|
||||
err = extractTestProxyArchive(archivePath, outputDir)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.Chmod(proxyPath, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Remove(archivePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func restoreRecordings(proxyPath string, pathToRecordings string) error {
|
||||
if pathToRecordings == "" {
|
||||
return nil
|
||||
}
|
||||
absAssetLocation, _, err := getAssetsConfigLocation(pathToRecordings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Running test proxy command: %s restore -a %s\n", proxyPath, absAssetLocation)
|
||||
cmd := exec.Command(proxyPath, "restore", "-a", absAssetLocation)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
return cmd.Wait()
|
||||
}
|
||||
|
||||
func ensureTestProxyInstalled(proxyVersion string, proxyPath string, proxyDir string, pathToRecordings string) error {
|
||||
lockFile := filepath.Join(os.TempDir(), "test-proxy-install.lock")
|
||||
log.Printf("Waiting to acquire test proxy install lock %s\n", lockFile)
|
||||
maxTries := 600 // Wait 1 minute
|
||||
var i int
|
||||
for i = 0; i < maxTries; i++ {
|
||||
lock, err := os.OpenFile(lockFile, os.O_CREATE|os.O_EXCL, 0600)
|
||||
if err != nil {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
// NOTE: the lockfile will not be removed on ctrl-c during download.
|
||||
// Go test seems to send an os.Interrupt signal on test setup completion, so if we
|
||||
// call os.Exit(1) on ctrl-c the tests will never run. If we don't call os.Exit(1),
|
||||
// the tests cannot be canceled.
|
||||
// Therefore, if ctrl-c is pressed during download, the user will have to manually
|
||||
// remove the lockfile in order to get the tests running again.
|
||||
defer func() {
|
||||
lock.Close()
|
||||
os.Remove(lockFile)
|
||||
}()
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if i >= maxTries {
|
||||
return fmt.Errorf("timed out waiting to acquire test proxy install lock. Ensure %s does not exist", lockFile)
|
||||
}
|
||||
|
||||
cmd := exec.Command(proxyPath, "--version")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Printf("Test proxy not detected at %s, downloading...\n", proxyPath)
|
||||
} else {
|
||||
// TODO: fix proxy CLI tool versioning output to match the actual version we download
|
||||
installedVersion := "1.0.0-dev." + strings.TrimSpace(string(out))
|
||||
if installedVersion == proxyVersion {
|
||||
log.Printf("Test proxy version %s already installed\n", proxyVersion)
|
||||
return restoreRecordings(proxyPath, pathToRecordings)
|
||||
} else {
|
||||
log.Printf("Test proxy version %s does not match required version %s\n",
|
||||
installedVersion, proxyVersion)
|
||||
}
|
||||
}
|
||||
|
||||
proxyFile, err := getTestProxyDownloadFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proxyDownloadPath := filepath.Join(proxyDir, proxyFile)
|
||||
archive, err := os.Create(proxyDownloadPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Downloading test proxy version %s to %s for %s/%s\n",
|
||||
proxyVersion, proxyPath, runtime.GOOS, runtime.GOARCH)
|
||||
proxyUrl := fmt.Sprintf("https://github.com/Azure/azure-sdk-tools/releases/download/Azure.Sdk.Tools.TestProxy_%s/%s",
|
||||
proxyVersion, proxyFile)
|
||||
resp, err := http.Get(proxyUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(archive, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = resp.Body.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = archive.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = installTestProxy(proxyDownloadPath, proxyDir, proxyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return restoreRecordings(proxyPath, pathToRecordings)
|
||||
}
|
||||
|
||||
func getProxyLog() (*os.File, error) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
const letters = "abcdefghijklmnopqrstuvwxyz"
|
||||
suffix := make([]byte, 6)
|
||||
for i := range suffix {
|
||||
suffix[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
proxyLogName := fmt.Sprintf("test-proxy.log.%s", suffix)
|
||||
proxyLog, err := os.Create(filepath.Join(os.TempDir(), proxyLogName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proxyLog, nil
|
||||
}
|
||||
|
||||
func getProxyVersion(gitRoot string) (string, error) {
|
||||
proxyVersionConfig := filepath.Join(gitRoot, "eng/common/testproxy/target_version.txt")
|
||||
version, err := ioutil.ReadFile(proxyVersionConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
proxyVersion := strings.TrimSpace(string(version))
|
||||
|
||||
return proxyVersion, nil
|
||||
}
|
||||
|
||||
func setTestProxyEnv(gitRoot string) {
|
||||
devCertPath := filepath.Join(gitRoot, "eng/common/testproxy/dotnet-devcert.pfx")
|
||||
os.Setenv("ASPNETCORE_Kestrel__Certificates__Default__Path", devCertPath)
|
||||
os.Setenv("ASPNETCORE_Kestrel__Certificates__Default__Password", "password")
|
||||
}
|
||||
|
||||
func waitForProxyStart(cmd *exec.Cmd, options *RecordingOptions) (*TestProxyInstance, error) {
|
||||
maxTries := 50
|
||||
// Extend sleep time in devops pipeline, proxy takes longer to start up
|
||||
if os.Getenv("SYSTEM_TEAMPROJECTID") != "" {
|
||||
maxTries = 200
|
||||
}
|
||||
log.Printf("Started test proxy instance (PID %d) on %s\n", cmd.Process.Pid, options.baseURL())
|
||||
client, _ := GetHTTPClient(nil)
|
||||
client.Timeout = 1 * time.Second
|
||||
|
||||
log.Printf("Waiting up to %d seconds for test-proxy server to respond...\n", (maxTries / 10))
|
||||
var i int
|
||||
for i = 0; i < maxTries; i++ {
|
||||
uri := fmt.Sprintf("https://localhost:%d/Admin/IsAlive", options.ProxyPort)
|
||||
req, _ := http.NewRequest("GET", uri, nil)
|
||||
req.Close = true
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if resp != nil && resp.Body != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return &TestProxyInstance{Cmd: cmd, Options: options}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("test proxy server did not become available in the allotted time")
|
||||
}
|
||||
|
||||
func StartTestProxy(pathToRecordings string, options *RecordingOptions) (*TestProxyInstance, error) {
|
||||
manualStart := strings.ToLower(os.Getenv(ProxyManualStartEnv))
|
||||
if manualStart == "true" {
|
||||
log.Printf("%s env variable is set to true, not starting test proxy...\n", ProxyManualStartEnv)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gitRoot, err := getGitRoot(cwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proxyVersion, err := getProxyVersion(gitRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proxyDir := filepath.Join(gitRoot, ".proxy")
|
||||
if err := os.MkdirAll(proxyDir, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proxyPath := filepath.Join(proxyDir, "Azure.Sdk.Tools.TestProxy")
|
||||
if runtime.GOOS == "windows" {
|
||||
proxyPath += ".exe"
|
||||
}
|
||||
err = ensureTestProxyInstalled(proxyVersion, proxyPath, proxyDir, pathToRecordings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proxyLog, err := getProxyLog()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer proxyLog.Close()
|
||||
|
||||
setTestProxyEnv(gitRoot)
|
||||
|
||||
if options == nil {
|
||||
options = defaultOptions()
|
||||
}
|
||||
log.Printf("Running test proxy command: %s start --storage-location %s -- --urls=%s\n",
|
||||
proxyPath, gitRoot, options.baseURL())
|
||||
log.Printf("Test proxy log location: %s\n", proxyLog.Name())
|
||||
cmd := exec.Command(
|
||||
proxyPath, "start", "--storage-location", gitRoot, "--", "--urls="+options.baseURL())
|
||||
|
||||
cmd.Stdout = proxyLog
|
||||
cmd.Stderr = proxyLog
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- cmd.Wait()
|
||||
}()
|
||||
|
||||
return waitForProxyStart(cmd, options)
|
||||
}
|
||||
|
||||
// NOTE: The process will be killed if the user hits ctrl-c mid-way through tests, as go will
|
||||
// kill child processes when the main process does not exit cleanly. No os.Interrupt handlers
|
||||
// need to be added after starting the proxy server in tests.
|
||||
func StopTestProxy(proxyInstance *TestProxyInstance) error {
|
||||
if proxyInstance == nil || proxyInstance.Cmd == nil || proxyInstance.Cmd.Process == nil {
|
||||
return nil
|
||||
}
|
||||
log.Printf("Stopping test proxy instance (PID %d) on %s\n", proxyInstance.Cmd.Process.Pid, proxyInstance.Options.baseURL())
|
||||
err := proxyInstance.Cmd.Process.Kill()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package recording
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type serverTests struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func TestServer(t *testing.T) {
|
||||
suite.Run(t, new(serverTests))
|
||||
}
|
||||
|
||||
func (s *serverTests) SetupSuite() {
|
||||
// Ignore manual start in pipeline tests, we always want to exercise install
|
||||
os.Setenv(ProxyManualStartEnv, "false")
|
||||
}
|
||||
|
||||
func (s *serverTests) TestProxyDownloadFile() {
|
||||
file, err := getTestProxyDownloadFile()
|
||||
require.NoError(s.T(), err)
|
||||
require.NotEmpty(s.T(), file)
|
||||
}
|
||||
|
||||
func (s *serverTests) TestExtractTestProxyZip() {
|
||||
zipFile, err := os.CreateTemp("", "test-extract-*.zip")
|
||||
require.NoError(s.T(), err)
|
||||
defer zipFile.Close()
|
||||
|
||||
// Create a new zip archive
|
||||
zipWriter := zip.NewWriter(zipFile)
|
||||
defer zipWriter.Close()
|
||||
}
|
||||
|
||||
func (s *serverTests) TestEnsureTestProxyInstalled() {
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(s.T(), err)
|
||||
gitRoot, err := getGitRoot(cwd)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
proxyDir := filepath.Join(os.TempDir(), ".proxy")
|
||||
proxyVersion, err := getProxyVersion(gitRoot)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = os.RemoveAll(proxyDir)
|
||||
require.NoError(s.T(), err)
|
||||
err = os.MkdirAll(proxyDir, 0755)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
proxyPath := filepath.Join(proxyDir, "Azure.Sdk.Tools.TestProxy")
|
||||
if runtime.GOOS == "windows" {
|
||||
proxyPath += ".exe"
|
||||
}
|
||||
|
||||
// Test download proxy
|
||||
err = ensureTestProxyInstalled(proxyVersion, proxyPath, proxyDir, "")
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
stat1, err := os.Stat(proxyPath)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// Test cached proxy
|
||||
err = ensureTestProxyInstalled(proxyVersion, proxyPath, proxyDir, "")
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
stat2, err := os.Stat(proxyPath)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
require.Equal(s.T(), stat1.ModTime(), stat2.ModTime(), "Expected proxy download to be cached")
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"Entries": [],
|
||||
"Variables": {
|
||||
"randSeed": "1676365801"
|
||||
"randSeed": "1689722394"
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"Entries": [
|
||||
{
|
||||
"RequestUri": "https://bing.com/",
|
||||
"RequestMethod": "POST",
|
||||
"RequestHeaders": {
|
||||
":method": "POST",
|
||||
"Accept-Encoding": "gzip",
|
||||
"Content-Length": "0",
|
||||
"User-Agent": "Go-http-client/2.0"
|
||||
},
|
||||
"RequestBody": null,
|
||||
"StatusCode": 301,
|
||||
"ResponseHeaders": {
|
||||
"Accept-CH": "Sec-CH-UA-Arch, Sec-CH-UA-Bitness, Sec-CH-UA-Full-Version, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version",
|
||||
"Cache-Control": "private",
|
||||
"Content-Encoding": "gzip",
|
||||
"Content-Length": "2943",
|
||||
"Content-Type": "text/html; charset=utf-8",
|
||||
"Date": "Thu, 17 Feb 2022 20:30:07 GMT",
|
||||
"Location": "https://www.bing.com/?toWww=1\u0026redig=81BB7CD9B29C416FB30ABD795D00AAF6\u0026toWww=1\u0026redig=CE7B5383D95F46FF947B2BC37CB68D6E\u0026toWww=1\u0026redig=CB8EFFEA2DCD459EB1E820873F6A0ED5\u0026toWww=1\u0026redig=66E6D5B1A52A42DAA48FCB45A1F58C7F\u0026toWww=1\u0026redig=1C900977865E48A3AE8A940E067B4360\u0026toWww=1\u0026redig=6ABF54D5B5E7420B93AB52A135102BB3\u0026toWww=1\u0026redig=D8EEC4D6F219451EA57C61AC8BBD3750\u0026toWww=1\u0026redig=CEEFBEA9597847EA9F7E199BDD5B628B\u0026toWww=1\u0026redig=7365DCE371C14626AD7A59CE7B01A342\u0026toWww=1\u0026redig=857F8622D57C4601AA117E048C2AB88A\u0026toWww=1\u0026redig=68DA9FADFEED465BA3E7D3380248665F\u0026toWww=1\u0026redig=ED3C1969DDB94E73A1BA017644325800\u0026toWww=1\u0026redig=24AEF3549F1945F9BD48015E6E753B1E\u0026toWww=1\u0026redig=9D107AB46F5C495B8667EE4808973116\u0026toWww=1\u0026redig=644D912599CE476DAFA9717B97E5EFD5\u0026toWww=1\u0026redig=63C86EAFEBDC465BBA15E04318FB4C22\u0026toWww=1\u0026redig=147FEF40AA4F423B9247902EB4D1D6C8\u0026toWww=1\u0026redig=8787BF0DE47248B5BA2B0CDA17B7BBEA\u0026toWww=1\u0026redig=782D6A378BE042CA8CEE385EA0A7ADF7\u0026toWww=1\u0026redig=A11ABEEA72D14BCE9FAA50AC3419CE6C\u0026toWww=1\u0026redig=4F151488BDF54D108D1B19A1F7D56C20\u0026toWww=1\u0026redig=E9CBC0E274224D859522A7D6E4D2EC80\u0026toWww=1\u0026redig=49622F30DE1F443BB2F568DE2E56766E\u0026toWww=1\u0026redig=8B043DABBA1A40D3B207456B4D103699\u0026toWww=1\u0026redig=5A095C4F102E40E8A6111644C70EFF5C\u0026toWww=1\u0026redig=BA559D266FF6435C98D9AE721A815C10\u0026toWww=1\u0026redig=314FCF35913F4F41B5A34499FBF36043\u0026toWww=1\u0026redig=FE196F2DE37247CAB08E84DC1BEE0AD1\u0026toWww=1\u0026redig=6A0FCED8A5FD4E26AB50BA70DA48CE18\u0026toWww=1\u0026redig=51EDFBCD545344AB83D2C4EE79F9B95C\u0026toWww=1\u0026redig=9C416419D8464C0B9DF4D597D2C93EC1\u0026toWww=1\u0026redig=EDF79189D66A4787957D8B2DFE6C639C\u0026toWww=1\u0026redig=0AB731BB5CD7447E841E3742540A92CC\u0026toWww=1\u0026redig=0CB28E343C654DEFAE62619A6759F149\u0026toWww=1\u0026redig=3299895DFC7D4BDFBF995FA7BF319831\u0026toWww=1\u0026redig=1DFD1169D5A44FA7B7C20F06149550D2\u0026toWww=1\u0026redig=3255FC6416DC45CDA44F3254FF8030AA\u0026toWww=1\u0026redig=1CEA595A81C240178409321330F67D4F\u0026toWww=1\u0026redig=6EFE965CFE0846D885553D444E36096C\u0026toWww=1\u0026redig=295135DAA5504F1095967A3392D68BFB\u0026toWww=1\u0026redig=6A141735E0704BD1A1D78AA09CF8B51B\u0026toWww=1\u0026redig=58C30338DCD24E84A9EBDF52FEA0A478\u0026toWww=1\u0026redig=DE5E02CD46A84B44A30A4EF8B2EBA4FF\u0026toWww=1\u0026redig=D940173748BD4AFCB9FD0D0CD6ACB637\u0026toWww=1\u0026redig=358C78D6DE7F4778A2B32756DED73B0E\u0026toWww=1\u0026redig=04B2279FC9DF43088287B9113903001C\u0026toWww=1\u0026redig=80076EF3515B43E58FC917D26035E114\u0026toWww=1\u0026redig=E8AECD73A97C44B089420D07DA1253D5\u0026toWww=1\u0026redig=4A36194C4D1148178DD4B1E5BF2DDE23\u0026toWww=1\u0026redig=BEFE121F45A8466BBD4C76D8E318744B\u0026toWww=1\u0026redig=1486C7748639437E80896BB1A36AA22B",
|
||||
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
|
||||
"Vary": "Accept-Encoding",
|
||||
"X-Cache": "CONFIG_NOCACHE",
|
||||
"X-MSEdge-Ref": "Ref A: 624295BD473146C09FA61B70DA6E8A0A Ref B: ASHEDGE1221 Ref C: 2022-02-17T20:30:07Z",
|
||||
"X-SNR-Routing": "1"
|
||||
},
|
||||
"ResponseBody": [
|
||||
"\u003Chtml\u003E\u003Chead\u003E\u003Ctitle\u003EObject moved\u003C/title\u003E\u003C/head\u003E\u003Cbody\u003E\r\n",
|
||||
"\u003Ch2\u003EObject moved to \u003Ca href=\u0022https://www.bing.com:443/?toWww=1\u0026amp;redig=81BB7CD9B29C416FB30ABD795D00AAF6\u0026amp;toWww=1\u0026amp;redig=CE7B5383D95F46FF947B2BC37CB68D6E\u0026amp;toWww=1\u0026amp;redig=CB8EFFEA2DCD459EB1E820873F6A0ED5\u0026amp;toWww=1\u0026amp;redig=66E6D5B1A52A42DAA48FCB45A1F58C7F\u0026amp;toWww=1\u0026amp;redig=1C900977865E48A3AE8A940E067B4360\u0026amp;toWww=1\u0026amp;redig=6ABF54D5B5E7420B93AB52A135102BB3\u0026amp;toWww=1\u0026amp;redig=D8EEC4D6F219451EA57C61AC8BBD3750\u0026amp;toWww=1\u0026amp;redig=CEEFBEA9597847EA9F7E199BDD5B628B\u0026amp;toWww=1\u0026amp;redig=7365DCE371C14626AD7A59CE7B01A342\u0026amp;toWww=1\u0026amp;redig=857F8622D57C4601AA117E048C2AB88A\u0026amp;toWww=1\u0026amp;redig=68DA9FADFEED465BA3E7D3380248665F\u0026amp;toWww=1\u0026amp;redig=ED3C1969DDB94E73A1BA017644325800\u0026amp;toWww=1\u0026amp;redig=24AEF3549F1945F9BD48015E6E753B1E\u0026amp;toWww=1\u0026amp;redig=9D107AB46F5C495B8667EE4808973116\u0026amp;toWww=1\u0026amp;redig=644D912599CE476DAFA9717B97E5EFD5\u0026amp;toWww=1\u0026amp;redig=63C86EAFEBDC465BBA15E04318FB4C22\u0026amp;toWww=1\u0026amp;redig=147FEF40AA4F423B9247902EB4D1D6C8\u0026amp;toWww=1\u0026amp;redig=8787BF0DE47248B5BA2B0CDA17B7BBEA\u0026amp;toWww=1\u0026amp;redig=782D6A378BE042CA8CEE385EA0A7ADF7\u0026amp;toWww=1\u0026amp;redig=A11ABEEA72D14BCE9FAA50AC3419CE6C\u0026amp;toWww=1\u0026amp;redig=4F151488BDF54D108D1B19A1F7D56C20\u0026amp;toWww=1\u0026amp;redig=E9CBC0E274224D859522A7D6E4D2EC80\u0026amp;toWww=1\u0026amp;redig=49622F30DE1F443BB2F568DE2E56766E\u0026amp;toWww=1\u0026amp;redig=8B043DABBA1A40D3B207456B4D103699\u0026amp;toWww=1\u0026amp;redig=5A095C4F102E40E8A6111644C70EFF5C\u0026amp;toWww=1\u0026amp;redig=BA559D266FF6435C98D9AE721A815C10\u0026amp;toWww=1\u0026amp;redig=314FCF35913F4F41B5A34499FBF36043\u0026amp;toWww=1\u0026amp;redig=FE196F2DE37247CAB08E84DC1BEE0AD1\u0026amp;toWww=1\u0026amp;redig=6A0FCED8A5FD4E26AB50BA70DA48CE18\u0026amp;toWww=1\u0026amp;redig=51EDFBCD545344AB83D2C4EE79F9B95C\u0026amp;toWww=1\u0026amp;redig=9C416419D8464C0B9DF4D597D2C93EC1\u0026amp;toWww=1\u0026amp;redig=EDF79189D66A4787957D8B2DFE6C639C\u0026amp;toWww=1\u0026amp;redig=0AB731BB5CD7447E841E3742540A92CC\u0026amp;toWww=1\u0026amp;redig=0CB28E343C654DEFAE62619A6759F149\u0026amp;toWww=1\u0026amp;redig=3299895DFC7D4BDFBF995FA7BF319831\u0026amp;toWww=1\u0026amp;redig=1DFD1169D5A44FA7B7C20F06149550D2\u0026amp;toWww=1\u0026amp;redig=3255FC6416DC45CDA44F3254FF8030AA\u0026amp;toWww=1\u0026amp;redig=1CEA595A81C240178409321330F67D4F\u0026amp;toWww=1\u0026amp;redig=6EFE965CFE0846D885553D444E36096C\u0026amp;toWww=1\u0026amp;redig=295135DAA5504F1095967A3392D68BFB\u0026amp;toWww=1\u0026amp;redig=6A141735E0704BD1A1D78AA09CF8B51B\u0026amp;toWww=1\u0026amp;redig=58C30338DCD24E84A9EBDF52FEA0A478\u0026amp;toWww=1\u0026amp;redig=DE5E02CD46A84B44A30A4EF8B2EBA4FF\u0026amp;toWww=1\u0026amp;redig=D940173748BD4AFCB9FD0D0CD6ACB637\u0026amp;toWww=1\u0026amp;redig=358C78D6DE7F4778A2B32756DED73B0E\u0026amp;toWww=1\u0026amp;redig=04B2279FC9DF43088287B9113903001C\u0026amp;toWww=1\u0026amp;redig=80076EF3515B43E58FC917D26035E114\u0026amp;toWww=1\u0026amp;redig=E8AECD73A97C44B089420D07DA1253D5\u0026amp;toWww=1\u0026amp;redig=4A36194C4D1148178DD4B1E5BF2DDE23\u0026amp;toWww=1\u0026amp;redig=BEFE121F45A8466BBD4C76D8E318744B\u0026amp;toWww=1\u0026amp;redig=1486C7748639437E80896BB1A36AA22B\u0022\u003Ehere\u003C/a\u003E.\u003C/h2\u003E\r\n",
|
||||
"\u003C/body\u003E\u003C/html\u003E\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Variables": {}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"Entries": [
|
||||
{
|
||||
"RequestUri": "https://bing.com/",
|
||||
"RequestMethod": "POST",
|
||||
"RequestHeaders": {
|
||||
":method": "POST",
|
||||
"Accept-Encoding": "gzip",
|
||||
"Content-Length": "0",
|
||||
"User-Agent": "Go-http-client/2.0"
|
||||
},
|
||||
"RequestBody": null,
|
||||
"StatusCode": 301,
|
||||
"ResponseHeaders": {
|
||||
"Accept-CH": "Sec-CH-UA-Arch, Sec-CH-UA-Bitness, Sec-CH-UA-Full-Version, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version",
|
||||
"Cache-Control": "private",
|
||||
"Content-Encoding": "gzip",
|
||||
"Content-Length": "2943",
|
||||
"Content-Type": "text/html; charset=utf-8",
|
||||
"Date": "Thu, 17 Feb 2022 20:30:13 GMT",
|
||||
"Location": "https://www.bing.com/?toWww=1\u0026redig=2BD048EA61C843BF858ECF8BA81F527E\u0026toWww=1\u0026redig=223C42F9DD15458584170A0103277F52\u0026toWww=1\u0026redig=8958623586264C269F2FA43A2E235593\u0026toWww=1\u0026redig=5B53A319EB244E8FACB75530BB793E9C\u0026toWww=1\u0026redig=E1B70FC75AF44ED382ABF5FE066867D5\u0026toWww=1\u0026redig=6C0D51C499254EE6A43250D8831DB8BF\u0026toWww=1\u0026redig=97D61E64FF1E463289FE355B9AE04D72\u0026toWww=1\u0026redig=929B3DF5252046D6A431309997E84853\u0026toWww=1\u0026redig=077B4C1EBFD94A20B3CC849876F63F13\u0026toWww=1\u0026redig=F64DF7F462BA4EF29CEF1EBE25399D12\u0026toWww=1\u0026redig=9B4C7D8B003D4E9EA580909984C9DDC5\u0026toWww=1\u0026redig=45689429E4044FC0A0FB1A715361B24A\u0026toWww=1\u0026redig=F4FE54C0951A440291601D6D1FA02D27\u0026toWww=1\u0026redig=BE8DBEC371AA48478038EC62AFE7D983\u0026toWww=1\u0026redig=E5A87AE1F00C499CBEEFAFED1F60DDED\u0026toWww=1\u0026redig=63F14CED1050430D8FB08507682A3990\u0026toWww=1\u0026redig=0BEB5406EB4D4C10BF4AD78B73D7360E\u0026toWww=1\u0026redig=E876ED4D917141A296E8321EF3AD0243\u0026toWww=1\u0026redig=D74AFD9C9D92427ABBC9D004DDE2F109\u0026toWww=1\u0026redig=3AF9AF2FC4FB4CAD94F473660F93E6BF\u0026toWww=1\u0026redig=1DFC418AF4E54E1EB6A11FCAD4635F4D\u0026toWww=1\u0026redig=6F4D8F465203478AA4A3A4B368816ACF\u0026toWww=1\u0026redig=E880D38280C648BEA2F29BF06C0F04DB\u0026toWww=1\u0026redig=56DDE4FDEE17496E9A8452AB09683574\u0026toWww=1\u0026redig=F8ACAFD5D67444E8812406E0AD13F86D\u0026toWww=1\u0026redig=5951262928414B5D96442BA5A0297B30\u0026toWww=1\u0026redig=F64B9013A94C46A8A5E672D25855E4B7\u0026toWww=1\u0026redig=FCA0EDE51D0046BAA71DCDACD20D8AA3\u0026toWww=1\u0026redig=EA7A8646EE9E41DA862E10F0E439325E\u0026toWww=1\u0026redig=1145E8376D544D70A4C3235B527E09E9\u0026toWww=1\u0026redig=22BDF6CCBEAC4B5FB49E552E5D734064\u0026toWww=1\u0026redig=65CA5ACF556748538C517B04C7599406\u0026toWww=1\u0026redig=EAE28C3A9DFC466EADC945568650E779\u0026toWww=1\u0026redig=95C5F5680BC844A385309F1DF5DA1A2E\u0026toWww=1\u0026redig=3C80C0D77CA14D69873147464CF7D8D0\u0026toWww=1\u0026redig=F9602FD488384082817470B482A7B6EB\u0026toWww=1\u0026redig=8085AB612674463F84146DBDC4B88417\u0026toWww=1\u0026redig=6D492C540C11437ABA9AF98CE157884D\u0026toWww=1\u0026redig=0CC0AAD83CC142D18A2FB38E756FB704\u0026toWww=1\u0026redig=AB2C0D3A5219429892E66BB676B32729\u0026toWww=1\u0026redig=752046EDE8AF48A19C8F7B56AB76F5D5\u0026toWww=1\u0026redig=358DFA1FDBDC4CF1A67AF4B51BFEEA16\u0026toWww=1\u0026redig=3DACA2E4587B47DA99F62E335314C9DE\u0026toWww=1\u0026redig=06CFC2438A794A9F8D1DE56B0CC2B332\u0026toWww=1\u0026redig=C8BB307EBF4E4B5393386023731897EA\u0026toWww=1\u0026redig=61638197A754402790E5EB9DB6F8CF57\u0026toWww=1\u0026redig=45027964670E458B95CD8902A6EB1278\u0026toWww=1\u0026redig=5E472A5E625D40EF9F108A1CB2870CFE\u0026toWww=1\u0026redig=0657C8E4009044559FB23B6D084C554B\u0026toWww=1\u0026redig=B960DBDF53F44E019A648FD713930E9A\u0026toWww=1\u0026redig=5D00DDCDB0754DB38306BE1CF3B84E92",
|
||||
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
|
||||
"Vary": "Accept-Encoding",
|
||||
"X-Cache": "CONFIG_NOCACHE",
|
||||
"X-MSEdge-Ref": "Ref A: 3F61F126A212460BB79BDF9FA51CB01D Ref B: ASHEDGE1221 Ref C: 2022-02-17T20:30:13Z",
|
||||
"X-SNR-Routing": "1"
|
||||
},
|
||||
"ResponseBody": [
|
||||
"\u003Chtml\u003E\u003Chead\u003E\u003Ctitle\u003EObject moved\u003C/title\u003E\u003C/head\u003E\u003Cbody\u003E\r\n",
|
||||
"\u003Ch2\u003EObject moved to \u003Ca href=\u0022https://www.bing.com:443/?toWww=1\u0026amp;redig=2BD048EA61C843BF858ECF8BA81F527E\u0026amp;toWww=1\u0026amp;redig=223C42F9DD15458584170A0103277F52\u0026amp;toWww=1\u0026amp;redig=8958623586264C269F2FA43A2E235593\u0026amp;toWww=1\u0026amp;redig=5B53A319EB244E8FACB75530BB793E9C\u0026amp;toWww=1\u0026amp;redig=E1B70FC75AF44ED382ABF5FE066867D5\u0026amp;toWww=1\u0026amp;redig=6C0D51C499254EE6A43250D8831DB8BF\u0026amp;toWww=1\u0026amp;redig=97D61E64FF1E463289FE355B9AE04D72\u0026amp;toWww=1\u0026amp;redig=929B3DF5252046D6A431309997E84853\u0026amp;toWww=1\u0026amp;redig=077B4C1EBFD94A20B3CC849876F63F13\u0026amp;toWww=1\u0026amp;redig=F64DF7F462BA4EF29CEF1EBE25399D12\u0026amp;toWww=1\u0026amp;redig=9B4C7D8B003D4E9EA580909984C9DDC5\u0026amp;toWww=1\u0026amp;redig=45689429E4044FC0A0FB1A715361B24A\u0026amp;toWww=1\u0026amp;redig=F4FE54C0951A440291601D6D1FA02D27\u0026amp;toWww=1\u0026amp;redig=BE8DBEC371AA48478038EC62AFE7D983\u0026amp;toWww=1\u0026amp;redig=E5A87AE1F00C499CBEEFAFED1F60DDED\u0026amp;toWww=1\u0026amp;redig=63F14CED1050430D8FB08507682A3990\u0026amp;toWww=1\u0026amp;redig=0BEB5406EB4D4C10BF4AD78B73D7360E\u0026amp;toWww=1\u0026amp;redig=E876ED4D917141A296E8321EF3AD0243\u0026amp;toWww=1\u0026amp;redig=D74AFD9C9D92427ABBC9D004DDE2F109\u0026amp;toWww=1\u0026amp;redig=3AF9AF2FC4FB4CAD94F473660F93E6BF\u0026amp;toWww=1\u0026amp;redig=1DFC418AF4E54E1EB6A11FCAD4635F4D\u0026amp;toWww=1\u0026amp;redig=6F4D8F465203478AA4A3A4B368816ACF\u0026amp;toWww=1\u0026amp;redig=E880D38280C648BEA2F29BF06C0F04DB\u0026amp;toWww=1\u0026amp;redig=56DDE4FDEE17496E9A8452AB09683574\u0026amp;toWww=1\u0026amp;redig=F8ACAFD5D67444E8812406E0AD13F86D\u0026amp;toWww=1\u0026amp;redig=5951262928414B5D96442BA5A0297B30\u0026amp;toWww=1\u0026amp;redig=F64B9013A94C46A8A5E672D25855E4B7\u0026amp;toWww=1\u0026amp;redig=FCA0EDE51D0046BAA71DCDACD20D8AA3\u0026amp;toWww=1\u0026amp;redig=EA7A8646EE9E41DA862E10F0E439325E\u0026amp;toWww=1\u0026amp;redig=1145E8376D544D70A4C3235B527E09E9\u0026amp;toWww=1\u0026amp;redig=22BDF6CCBEAC4B5FB49E552E5D734064\u0026amp;toWww=1\u0026amp;redig=65CA5ACF556748538C517B04C7599406\u0026amp;toWww=1\u0026amp;redig=EAE28C3A9DFC466EADC945568650E779\u0026amp;toWww=1\u0026amp;redig=95C5F5680BC844A385309F1DF5DA1A2E\u0026amp;toWww=1\u0026amp;redig=3C80C0D77CA14D69873147464CF7D8D0\u0026amp;toWww=1\u0026amp;redig=F9602FD488384082817470B482A7B6EB\u0026amp;toWww=1\u0026amp;redig=8085AB612674463F84146DBDC4B88417\u0026amp;toWww=1\u0026amp;redig=6D492C540C11437ABA9AF98CE157884D\u0026amp;toWww=1\u0026amp;redig=0CC0AAD83CC142D18A2FB38E756FB704\u0026amp;toWww=1\u0026amp;redig=AB2C0D3A5219429892E66BB676B32729\u0026amp;toWww=1\u0026amp;redig=752046EDE8AF48A19C8F7B56AB76F5D5\u0026amp;toWww=1\u0026amp;redig=358DFA1FDBDC4CF1A67AF4B51BFEEA16\u0026amp;toWww=1\u0026amp;redig=3DACA2E4587B47DA99F62E335314C9DE\u0026amp;toWww=1\u0026amp;redig=06CFC2438A794A9F8D1DE56B0CC2B332\u0026amp;toWww=1\u0026amp;redig=C8BB307EBF4E4B5393386023731897EA\u0026amp;toWww=1\u0026amp;redig=61638197A754402790E5EB9DB6F8CF57\u0026amp;toWww=1\u0026amp;redig=45027964670E458B95CD8902A6EB1278\u0026amp;toWww=1\u0026amp;redig=5E472A5E625D40EF9F108A1CB2870CFE\u0026amp;toWww=1\u0026amp;redig=0657C8E4009044559FB23B6D084C554B\u0026amp;toWww=1\u0026amp;redig=B960DBDF53F44E019A648FD713930E9A\u0026amp;toWww=1\u0026amp;redig=5D00DDCDB0754DB38306BE1CF3B84E92\u0022\u003Ehere\u003C/a\u003E.\u003C/h2\u003E\r\n",
|
||||
"\u003C/body\u003E\u003C/html\u003E\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Variables": {}
|
||||
}
|
Загрузка…
Ссылка в новой задаче