From a01c2b7a261ff30318c67727d246259d60b32fd7 Mon Sep 17 00:00:00 2001 From: btfhernandez <133419363+btfhernandez@users.noreply.github.com> Date: Fri, 8 Mar 2024 13:34:53 -0500 Subject: [PATCH] feat: add performance test (#56) authored-by: EPAM\Felipe_Hernandez --- .github/workflows/release.yml | 4 +- README.md | 26 +++++++ go.mod | 2 - performancetest/PerformanceTest.go | 113 +++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 performancetest/PerformanceTest.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 729ca49..9eb10a9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -72,7 +72,7 @@ jobs: -Dsonar.pullrequest.branch=${{ github.head_ref }} -Dsonar.pullrequest.base=${{ github.base_ref }} -Dsonar.go.coverage.reportPaths=coverage.out - -Dsonar.exclusions=api/**/**_test.go,api/entities/**,api/logging/**,api/utils/**,TestClient.go + -Dsonar.exclusions=api/**/**_test.go,api/entities/**,api/logging/**,api/utils/**,TestClient.go,performancetest/PerformanceTest.go env: SONAR_TOKEN: ${{ env.SONAR_TOKEN }} SONAR_HOST_URL: https://sonar.dev.beyondtrust.com @@ -85,7 +85,7 @@ jobs: args: > -Dsonar.projectKey=${{ github.event.repository.name }} -Dsonar.go.coverage.reportPaths=coverage.out - -Dsonar.exclusions=api/**/**_test.go,api/entities/**,api/logging/**,api/utils/**,TestClient.go + -Dsonar.exclusions=api/**/**_test.go,api/entities/**,api/logging/**,api/utils/**,TestClient.go,performancetest/PerformanceTest.go env: SONAR_TOKEN: ${{ env.SONAR_TOKEN }} SONAR_HOST_URL: https://sonar.dev.beyondtrust.com diff --git a/README.md b/README.md index 7023634..31e6c88 100644 --- a/README.md +++ b/README.md @@ -158,3 +158,29 @@ Some of the more important and common commit types are: | ci | Changes to CI configuration files and scripts | No | Remember, Release Please App will trigger once a PR with the conventional commit structure are merged into the main branch, so if you are working on features that are related to a Jira ticket, you can still use **feat** while developing, and because we can squash the commits once we want to merge the PR, only one commit with the conventional syntax will be on the history and on the changelog. + +## Performance Tests + +Run performance Tests + +```bash +go run performancetest/PerformanceTest.go +``` + +In Other console run + +```bash +# run web UI +go tool pprof -http=:8080 memory.pprof +go tool pprof -http=:8081 cpu.pprof + +# run with not web UI +go tool pprof memory.pprof +go tool pprof cpu.pprof + +# check functions memory and cpu usage +top + +# go inside of function memory usage +list main.callPasswordSafeAPI +``` diff --git a/go.mod b/go.mod index b155d81..99275b2 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module go-client-library-passwordsafe go 1.21 -toolchain go1.22.0 - require ( github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect diff --git a/performancetest/PerformanceTest.go b/performancetest/PerformanceTest.go new file mode 100644 index 0000000..f95b984 --- /dev/null +++ b/performancetest/PerformanceTest.go @@ -0,0 +1,113 @@ +package main + +import ( + "fmt" + "go-client-library-passwordsafe/api/authentication" + "go-client-library-passwordsafe/api/logging" + "go-client-library-passwordsafe/api/secrets" + "go-client-library-passwordsafe/api/utils" + "net/http" + _ "net/http/pprof" + "os" + "runtime/pprof" + "time" + + backoff "github.com/cenkalti/backoff/v4" + "go.uber.org/zap" +) + +// number of PS API calls +const numberOfIterations = 5 + +func main() { + go func() { + err := http.ListenAndServe("localhost:6060", nil) + if err != nil { + panic(err) + } + }() + + // CPU + f, err := os.Create("cpu.pprof") + if err != nil { + panic(err) + } + defer f.Close() + + err = pprof.StartCPUProfile(f) + if err != nil { + panic(err) + } + defer pprof.StopCPUProfile() + + for i := 0; i < numberOfIterations-1; i++ { + time.Sleep(100 * time.Millisecond) + callPasswordSafeAPI() + + } + + // MEMORY: Take a memory snapshot + f, _ = os.Create("memory.pprof") + err = pprof.WriteHeapProfile(f) + if err != nil { + panic(err) + } + + f.Close() +} + +// Method to be tested +func callPasswordSafeAPI() { + logger, _ := zap.NewDevelopment() + + // create a zap logger wrapper + zapLogger := logging.NewZapLogger(logger) + + zapLogger.Info("Starting flow") + apiUrl := "https://example.com:443/BeyondTrust/api/public/v3/" + clientId := "" + clientSecret := "" + separator := "/" + certificate := "" + certificateKey := "" + clientTimeOutInSeconds := 5 + verifyCa := true + retryMaxElapsedTimeMinutes := 15 + maxFileSecretSizeBytes := 5000000 + + // validate inputs + errorsInInputs := utils.ValidateInputs(clientId, clientSecret, &apiUrl, clientTimeOutInSeconds, &separator, verifyCa, zapLogger, certificate, certificateKey, &retryMaxElapsedTimeMinutes, &maxFileSecretSizeBytes) + if errorsInInputs != nil { + return + } + + // creating a http client + httpClientObj, _ := utils.GetHttpClient(clientTimeOutInSeconds, verifyCa, certificate, certificateKey, zapLogger) + + backoffDefinition := backoff.NewExponentialBackOff() + backoffDefinition.InitialInterval = 1 * time.Second + backoffDefinition.MaxElapsedTime = time.Duration(retryMaxElapsedTimeMinutes) * time.Second + backoffDefinition.RandomizationFactor = 0.5 + + // instantiating authenticate obj, injecting httpClient object + authenticate, _ := authentication.Authenticate(*httpClientObj, backoffDefinition, apiUrl, clientId, clientSecret, zapLogger, retryMaxElapsedTimeMinutes) + + // authenticating + _, err := authenticate.GetPasswordSafeAuthentication() + if err != nil { + return + } + + // instantiating secret obj + secretObj, _ := secrets.NewSecretObj(*authenticate, zapLogger, maxFileSecretSizeBytes) + + // getting single secret + gotSecret, _ := secretObj.GetSecret("oauthgrp/folder1/folder2/folder 3/folder4/folder5/folder6/Text-Test", separator) + + // WARNING: Do not log secrets in production code, the following log statement logs test secrets for testing purposes: + zapLogger.Warn(fmt.Sprintf("%v", gotSecret)) + + // signing out + _ = authenticate.SignOut(authenticate.ApiUrl.JoinPath("Auth/Signout").String()) + +}