Skip to content

Commit

Permalink
Add testing, and download from RUM unreleased modules (#123)
Browse files Browse the repository at this point in the history
Add testing, and download from RUM unreleased modules
  • Loading branch information
pablomartinezbernardo authored Oct 2, 2024
1 parent 9440247 commit cacad6b
Show file tree
Hide file tree
Showing 23 changed files with 1,718 additions and 747 deletions.
746 changes: 10 additions & 736 deletions .circleci/config.yml

Large diffs are not rendered by default.

788 changes: 788 additions & 0 deletions .circleci/continue_config.yml

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions installer/configurator/configurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
log "github.com/sirupsen/logrus"
)

var InstallerVersion = "0.1.0"
var InstallerVersion = "0.1.1"

func validateInput(appID, site, clientToken, arch string, sessionSampleRate, sessionReplaySampleRate int) error {

Expand Down Expand Up @@ -54,9 +54,14 @@ func main() {
skipVerify := flag.Bool("skipVerify", false, "Skip verifying downloads")
verbose := flag.Bool("verbose", false, "Verbose output")
dryRun := flag.Bool("dryRun", false, "Dry run (no changes made)")
skipDownload := flag.Bool("skipDownload", false, "Skip the download of this installer and use a local binary instead")

flag.Parse()

if *skipDownload {
log.Info("Download was skipped, used local binary")
}

if *verbose {
log.SetLevel(log.DebugLevel)
log.Debug("Verbose output enabled")
Expand Down Expand Up @@ -93,6 +98,6 @@ func main() {
handleError(err)
}

log.Info("Datadog NGINX module has been successfully installed and configured. Please restart NGINX for the changes to take effect")
log.Info("Datadog NGINX module has been successfully installed and configured. Please reload NGINX or restart the service for the changes to take effect")
}
}
138 changes: 138 additions & 0 deletions installer/configurator/configurator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package main

import (
"strings"
"testing"
)

func TestValidateInput(t *testing.T) {
tests := []struct {
name string
appID string
site string
clientToken string
arch string
sessionSampleRate int
sessionReplaySampleRate int
expectedError string
}{
{
name: "Valid input",
appID: "test-app",
site: "test-site",
clientToken: "test-token",
arch: "amd64",
sessionSampleRate: 50,
sessionReplaySampleRate: 50,
expectedError: "",
},
{
name: "Empty appID",
appID: "",
site: "test-site",
clientToken: "test-token",
arch: "amd64",
sessionSampleRate: 50,
sessionReplaySampleRate: 50,
expectedError: "--appId is required",
},
{
name: "Empty site",
appID: "test-app",
site: "",
clientToken: "test-token",
arch: "amd64",
sessionSampleRate: 50,
sessionReplaySampleRate: 50,
expectedError: "--site is required",
},
{
name: "Empty clientToken",
appID: "test-app",
site: "test-site",
clientToken: "",
arch: "amd64",
sessionSampleRate: 50,
sessionReplaySampleRate: 50,
expectedError: "--clientToken is required",
},
{
name: "Invalid sessionSampleRate (negative)",
appID: "test-app",
site: "test-site",
clientToken: "test-token",
arch: "amd64",
sessionSampleRate: -1,
sessionReplaySampleRate: 50,
expectedError: "sessionSampleRate is required and must be between 0 and 100",
},
{
name: "Invalid sessionSampleRate (over 100)",
appID: "test-app",
site: "test-site",
clientToken: "test-token",
arch: "amd64",
sessionSampleRate: 101,
sessionReplaySampleRate: 50,
expectedError: "sessionSampleRate is required and must be between 0 and 100",
},
{
name: "Invalid sessionReplaySampleRate (negative)",
appID: "test-app",
site: "test-site",
clientToken: "test-token",
arch: "amd64",
sessionSampleRate: 50,
sessionReplaySampleRate: -1,
expectedError: "sessionReplaySampleRate is required and must be between 0 and 100",
},
{
name: "Invalid sessionReplaySampleRate (over 100)",
appID: "test-app",
site: "test-site",
clientToken: "test-token",
arch: "amd64",
sessionSampleRate: 50,
sessionReplaySampleRate: 101,
expectedError: "sessionReplaySampleRate is required and must be between 0 and 100",
},
{
name: "Invalid arch",
appID: "test-app",
site: "test-site",
clientToken: "test-token",
arch: "x86",
sessionSampleRate: 50,
sessionReplaySampleRate: 50,
expectedError: "arch must be either 'amd64' or 'arm64'",
},
{
name: "Valid input with arm64 arch",
appID: "test-app",
site: "test-site",
clientToken: "test-token",
arch: "arm64",
sessionSampleRate: 50,
sessionReplaySampleRate: 50,
expectedError: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validateInput(tt.appID, tt.site, tt.clientToken, tt.arch, tt.sessionSampleRate, tt.sessionReplaySampleRate)

if tt.expectedError == "" {
if err != nil {
t.Errorf("Expected no error, but got: %v", err)
}
} else {
if err == nil {
t.Errorf("Expected error containing '%s', but got no error", tt.expectedError)
} else if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error containing '%s', but got: %v", tt.expectedError, err)
}
}
})
}
}
8 changes: 7 additions & 1 deletion installer/configurator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ require (
github.com/google/go-github v17.0.0+incompatible
github.com/google/uuid v1.6.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
gotest.tools v2.2.0+incompatible
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-cmp v0.5.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.22.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
6 changes: 6 additions & 0 deletions installer/configurator/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
Expand All @@ -20,8 +22,12 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
7 changes: 5 additions & 2 deletions installer/configurator/nginx_configurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ func (n *NginxConfigurator) DownloadAndInstallModule(arch string, skipVerify boo
return err
}

moduleURL := fmt.Sprintf("https://github.com/DataDog/nginx-datadog/releases/latest/download/ngx_http_datadog_module-%s-%s.so.tgz", arch, n.Version)
// TODO: Use the releases once the module is actually released with RUM
// baseURL := fmt.Sprintf("https://github.com/DataDog/nginx-datadog/releases/latest/download/")
baseURL := "https://ddagent-windows-unstable.s3.amazonaws.com/inject-browser-sdk/nginx/latest/"
moduleURL := baseURL + fmt.Sprintf("ngx_http_datadog_module-%s-%s.so.tgz", arch, n.Version)

moduleContent, err := downloadFile(moduleURL)
if err != nil {
Expand Down Expand Up @@ -174,7 +177,7 @@ func (n *NginxConfigurator) DownloadAndInstallModule(arch string, skipVerify boo

log.Debug("Downloaded signature file: ", signatureURL)

publicKeyURL := "https://github.com/DataDog/nginx-datadog/releases/latest/download/pubkey.gpg"
publicKeyURL := baseURL + "pubkey.gpg"
publicKeyContent, err := downloadFile(publicKeyURL)
if err != nil {
return NewInstallerError(NginxError, fmt.Errorf("failed to download public key: %v", err))
Expand Down
82 changes: 82 additions & 0 deletions installer/configurator/nginx_configurator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/require"
"gotest.tools/assert"
)

type FileInfo struct {
Filename string
IsError bool
}

func TestTransformConfigSnapshot(t *testing.T) {
const modulesPath = "/opt/datadog-nginx"
const agentUri = "http://localhost:8126"
const appId = "ffffffff-ffff-ffff-ffff-ffffffffffff"
const clientToken = "pubffffffffffffffffffffffffffffffff"
const site = "datadoghq.com"
const sessionSampleRate = 49
const sessionReplaySampleRate = 51

pattern := filepath.Join("testdata", "*.conf")
files, err := filepath.Glob(pattern)
require.NoError(t, err, "Failed to list test cases")

// List all test cases
// *.conf should contain a corresponding *.conf.snap file, created if not exists
// *.err.conf should fail the transformation, no corresponding snapshot file
var testCases []FileInfo
for _, file := range files {
isError := strings.HasSuffix(filepath.Base(file), ".err.conf")
testCases = append(testCases, FileInfo{
Filename: file,
IsError: isError,
})
}

for _, tc := range testCases {
t.Run(tc.Filename, func(t *testing.T) {
input, err := os.ReadFile(tc.Filename)
require.NoError(t, err, "Failed to read input file")

// Create a temporary file for the output
tmpFile, err := os.CreateTemp("", "nginx-config-*.conf")
require.NoError(t, err, "Failed to create temporary file")
defer os.Remove(tmpFile.Name())

configurator := &NginxConfigurator{
ModulesPath: modulesPath,
}

transformed, err := transformConfig(configurator, input, agentUri, appId, clientToken, site, sessionSampleRate, sessionReplaySampleRate, tmpFile.Name())
if tc.IsError {
require.Error(t, err, "Expected an error transforming the configuration, it succeeded instead")
return
}

require.NoError(t, err, "Failed to transform config")

snapshotFile := filepath.Join("testdata", filepath.Base(tc.Filename)+".snap")

if _, err := os.Stat(snapshotFile); os.IsNotExist(err) {
// If snapshot doesn't exist, create it for local use, fail the test
err = os.WriteFile(snapshotFile, transformed, 0644)
require.NoError(t, err, "Failed to create snapshot file")
t.Logf("Created new snapshot: %s", snapshotFile)
t.Fail()
} else {
// If snapshot exists, compare with it
expected, err := os.ReadFile(snapshotFile)
require.NoError(t, err, "Failed to read snapshot file")

assert.Equal(t, string(expected), string(transformed), "Transformed config does not match snapshot")
}
})
}
}
31 changes: 31 additions & 0 deletions installer/configurator/testdata/basic.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;


events {
worker_connections 1024;
}


http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

#gzip on;

include /etc/nginx/conf.d/*.conf;
}
48 changes: 48 additions & 0 deletions installer/configurator/testdata/basic.conf.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
load_module /opt/datadog-nginx/ngx_http_datadog_module.so;
user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;


events {
worker_connections 1024;
}


http {
datadog_agent_url http://localhost:8126;

# Disable APM Tracing. Remove the next line to enable APM Tracing.
datadog_disable;

# Enable RUM Injection
datadog_rum on;

datadog_rum_config "v5" {
"applicationId" "ffffffff-ffff-ffff-ffff-ffffffffffff";
"clientToken" "pubffffffffffffffffffffffffffffffff";
"site" "datadoghq.com";
"sessionSampleRate" "49";
"sessionReplaySampleRate" "51";
}

include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

#gzip on;

include /etc/nginx/conf.d/*.conf;
}
Loading

0 comments on commit cacad6b

Please sign in to comment.