From 93e64c847ffffd52d25f51f79139995f03239202 Mon Sep 17 00:00:00 2001 From: Alvaro Cabanas Date: Fri, 9 Feb 2024 14:50:17 +0100 Subject: [PATCH] Add possibility to define a custom folder for temporary files. (#305) --- .github/workflows/test.yml | 29 +++++++++++++++++++++++++++ args/args.go | 13 ++++++------ data/metric/metrics_test.go | 4 ++-- data/metric/source_type_test.go | 2 +- docs/toolset/args.md | 1 + integration/integration.go | 2 +- integration/integration_test.go | 4 ++-- integration/options_test.go | 2 +- jmx/jmx_test.go | 6 ++---- persist/store_path.go | 4 ++-- persist/store_path_test.go | 35 +++++++++++++++++++++++++-------- persist/storer.go | 12 +++++++---- 12 files changed, 83 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..ecb3d334 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,29 @@ +name: UnitTesting + +on: [push, pull_request] + +env: + GO111MODULE: off + +jobs: + + build: + name: Build + runs-on: ubuntu-latest + defaults: + run: + working-directory: src/github.com/newrelic/infra-integrations-sdk + steps: + + - name: Set up Go + uses: actions/setup-go@v2 + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + with: + path: src/github.com/newrelic/infra-integrations-sdk + + - name: Test + env: + GOPATH: "${{ github.workspace }}" + run: env PATH="$PATH:$GOPATH/bin" make test diff --git a/args/args.go b/args/args.go index 9fae756c..08aca0fd 100644 --- a/args/args.go +++ b/args/args.go @@ -23,6 +23,7 @@ type DefaultArgumentList struct { NriAddHostname bool `default:"false" help:"Add hostname attribute to the samples."` NriCluster string `default:"" help:"Optional. Cluster name"` NriService string `default:"" help:"Optional. Service name"` + TempDir string `default:"" help:"Optional. Integrations path to store temporal data (defaults to os.tempDir if left empty)."` } // All returns if all data should be published @@ -81,12 +82,12 @@ func underscore(s string) string { // fields it defines. Each of the fields in the struct can define their defaults // and help string by using tags: // -// type Arguments struct { -// DefaultArgumentList -// Argument1 bool `default:"false" help:"This is the help we will print"` -// Argument2 int `default:"1" help:"This is the help we will print"` -// Argument3 string `default:"value" help:"This is the help we will print"` -// } +// type Arguments struct { +// DefaultArgumentList +// Argument1 bool `default:"false" help:"This is the help we will print"` +// Argument2 int `default:"1" help:"This is the help we will print"` +// Argument3 string `default:"value" help:"This is the help we will print"` +// } // // The fields in the struct will be populated with the values set either from // the command line or from environment variables. diff --git a/data/metric/metrics_test.go b/data/metric/metrics_test.go index 92fff31e..3bb5ceb3 100644 --- a/data/metric/metrics_test.go +++ b/data/metric/metrics_test.go @@ -130,7 +130,7 @@ func TestSet_SetMetricsRatesAndDeltas(t *testing.T) { } for _, tc := range testCases { - t.Run(string(tc.sourceType), func(t *testing.T) { + t.Run(tc.sourceType.String(), func(t *testing.T) { persist.SetNow(growingTime) @@ -145,7 +145,7 @@ func TestSet_SetMetricsRatesAndDeltas(t *testing.T) { func TestSet_SetMetricPositivesThrowsOnNegativeValues(t *testing.T) { for _, sourceType := range []SourceType{PDELTA, PRATE} { - t.Run(string(sourceType), func(t *testing.T) { + t.Run(sourceType.String(), func(t *testing.T) { persist.SetNow(growingTime) ms := NewSet( "some-event-type", diff --git a/data/metric/source_type_test.go b/data/metric/source_type_test.go index f526db83..b228a006 100644 --- a/data/metric/source_type_test.go +++ b/data/metric/source_type_test.go @@ -25,7 +25,7 @@ func TestSourceType_Positive(t *testing.T) { } for _, tc := range testCases { - t.Run(string(tc.sourceType), func(t *testing.T) { + t.Run(tc.sourceType.String(), func(t *testing.T) { assert.Equal(t, tc.isPositive, tc.sourceType.IsPositive()) }) } diff --git a/docs/toolset/args.md b/docs/toolset/args.md index d2319e7d..65933b8c 100644 --- a/docs/toolset/args.md +++ b/docs/toolset/args.md @@ -34,6 +34,7 @@ consider. All of them are `bool` and default to `false`. They are described foll * `NriAddHostname`: if true, agent will decorate all the metrics with the `hostname`. * `NriCluster`: if any value is provided, all the metrics will be decorated with `clusterName: value`. * `NriService`: if any value is provided, all the metrics will be decorated with `serviceName: value`. +* `TempDir`: Integrations path to store temporal data (it defaults to `os.TempDir()` if it's left empty). An example of diff --git a/integration/integration.go b/integration/integration.go index 044d708f..b4698f04 100644 --- a/integration/integration.go +++ b/integration/integration.go @@ -100,7 +100,7 @@ func New(name, version string, opts ...Option) (i *Integration, err error) { } if i.storer == nil { - storePath, err := persist.NewStorePath(i.Name, i.CreateUniqueID(), i.logger, persist.DefaultTTL) + storePath, err := persist.NewStorePath(i.Name, i.CreateUniqueID(), defaultArgs.TempDir, i.logger, persist.DefaultTTL) if err != nil { return nil, fmt.Errorf("can't create temporary directory for store: %s", err) } diff --git a/integration/integration_test.go b/integration/integration_test.go index ad82f63b..5c0f1dac 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -464,7 +464,7 @@ func TestIntegration_CreateUniqueID_Default(t *testing.T) { i, err := New("testIntegration", "0.0.0", Args(&al)) assert.NoError(t, err) - assert.Equal(t, i.CreateUniqueID(), "3071eb6863e28435e6c7e0c2bbe55ecd") + assert.Equal(t, i.CreateUniqueID(), "f2fbf79d935a14908cb886e98cff0879") } func TestIntegration_CreateUniqueID_EnvironmentVar(t *testing.T) { @@ -481,7 +481,7 @@ func TestIntegration_CreateUniqueID_EnvironmentVar(t *testing.T) { i, err := New("testIntegration", "0.0.0", Args(&al)) assert.NoError(t, err) - assert.Equal(t, i.CreateUniqueID(), "2d998100982b7de9b4e446c85c3bed78") + assert.Equal(t, i.CreateUniqueID(), "3d3c4d31fdec9ccd1250c9d080ca514f") } type testWriter struct { diff --git a/integration/options_test.go b/integration/options_test.go index 7123a4af..fb8bb941 100644 --- a/integration/options_test.go +++ b/integration/options_test.go @@ -72,7 +72,7 @@ func TestItStoresOnDiskByDefault(t *testing.T) { assert.NoError(t, i.Publish()) // assert data has been flushed to disk - storePath, err := persist.NewStorePath(i.Name, i.CreateUniqueID(), i.logger, persist.DefaultTTL) + storePath, err := persist.NewStorePath(i.Name, i.CreateUniqueID(), "", i.logger, persist.DefaultTTL) assert.NoError(t, err) c, err := persist.NewFileStore(storePath.GetFilePath(), log.NewStdErr(true), persist.DefaultTTL) diff --git a/jmx/jmx_test.go b/jmx/jmx_test.go index 328c844a..85e699cc 100644 --- a/jmx/jmx_test.go +++ b/jmx/jmx_test.go @@ -123,8 +123,6 @@ func TestQuery_WithSSL(t *testing.T) { } func TestOpen_WithNrjmx(t *testing.T) { - defer Close() - aux := os.Getenv("NR_JMX_TOOL") require.NoError(t, os.Unsetenv("NR_JMX_TOOL")) @@ -242,14 +240,14 @@ func Test_DefaultPath_IsCorrectForOs(t *testing.T) { } func TestHostName(t *testing.T) { - defer Close() + cmd = nil host := "a-host" assert.NoError(t, OpenNoAuth(host, "")) assert.Equal(t, host, HostName()) } func TestPort(t *testing.T) { - defer Close() + cmd = nil port := "6666" assert.NoError(t, OpenNoAuth("", port)) assert.Equal(t, port, Port()) diff --git a/persist/store_path.go b/persist/store_path.go index a62e1486..99e38927 100644 --- a/persist/store_path.go +++ b/persist/store_path.go @@ -28,7 +28,7 @@ type storePath struct { } // NewStorePath create a new instance of StorePath -func NewStorePath(integrationName, integrationID string, ilog log.Logger, ttl time.Duration) (StorePath, error) { +func NewStorePath(integrationName, integrationID, customTempDir string, ilog log.Logger, ttl time.Duration) (StorePath, error) { if integrationName == "" { return nil, fmt.Errorf("integration name not specified") } @@ -42,7 +42,7 @@ func NewStorePath(integrationName, integrationID string, ilog log.Logger, ttl ti } return &storePath{ - dir: tmpIntegrationDir(), + dir: tmpIntegrationDir(customTempDir), integrationName: integrationName, integrationID: integrationID, ilog: ilog, diff --git a/persist/store_path_test.go b/persist/store_path_test.go index 787b4aec..f1048994 100644 --- a/persist/store_path_test.go +++ b/persist/store_path_test.go @@ -15,7 +15,7 @@ func setupTestCase(t *testing.T) func(t *testing.T) { t.Log("setup test case") assert.NoError(t, os.RemoveAll(filepath.Join(os.TempDir(), integrationsDir))) - tmpDir = tmpIntegrationDir() + tmpDir = tmpIntegrationDir("") files := []struct { name string @@ -61,7 +61,7 @@ func TestStorePath_CleanOldFiles(t *testing.T) { defer tearDownFn(t) // WHEN new store file is generated - newPath, err := NewStorePath("com.newrelic.fake", "c", log.Discard, 1*time.Minute) + newPath, err := NewStorePath("com.newrelic.fake", "c", "", log.Discard, 1*time.Minute) assert.NoError(t, err) // THEN only old files with different integration ID are removed @@ -79,20 +79,39 @@ func TestStorePath_CleanOldFiles(t *testing.T) { } func TestStorePath_GetFilePath(t *testing.T) { - storeFile, err := NewStorePath("com.newrelic.fake", "c", log.Discard, 1*time.Minute) - assert.NoError(t, err) + cases := []struct { + tempDir string + expected string + }{ + { + tempDir: "", + expected: filepath.Join(tmpIntegrationDir(""), "com.newrelic.fake-c.json"), + }, + { + tempDir: "", + expected: filepath.Join(tmpIntegrationDir(os.TempDir()), "com.newrelic.fake-c.json"), + }, + { + tempDir: "custom-tmp", + expected: filepath.Join(tmpIntegrationDir("custom-tmp"), "com.newrelic.fake-c.json"), + }, + } - expected := filepath.Join(tmpIntegrationDir(), "com.newrelic.fake-c.json") - assert.Equal(t, expected, storeFile.GetFilePath()) + for _, tt := range cases { + storeFile, err := NewStorePath("com.newrelic.fake", "c", tt.tempDir, log.Discard, 1*time.Minute) + assert.NoError(t, err) + + assert.Equal(t, tt.expected, storeFile.GetFilePath()) + } } func TestStorePath_glob(t *testing.T) { - storeFile, err := NewStorePath("com.newrelic.fake", "c", log.Discard, 1*time.Minute) + storeFile, err := NewStorePath("com.newrelic.fake", "c", "", log.Discard, 1*time.Minute) assert.NoError(t, err) tmp, ok := storeFile.(*storePath) assert.True(t, ok) - expected := filepath.Join(tmpIntegrationDir(), "com.newrelic.fake-*.json") + expected := filepath.Join(tmpIntegrationDir(""), "com.newrelic.fake-*.json") assert.Equal(t, expected, tmp.glob()) } diff --git a/persist/storer.go b/persist/storer.go index 8e0f7056..11314553 100644 --- a/persist/storer.go +++ b/persist/storer.go @@ -77,17 +77,21 @@ func SetNow(newNow func() time.Time) { // DefaultPath returns a default folder/filename dir to a Storer for an integration from the given name. The name of // the file will be the name of the integration with the .json extension. func DefaultPath(integrationName string) string { - dir := tmpIntegrationDir() + dir := tmpIntegrationDir("") file := filepath.Join(dir, integrationName+".json") return file } -func tmpIntegrationDir() string { - dir := filepath.Join(os.TempDir(), integrationsDir) +func tmpIntegrationDir(tempDir string) string { + if tempDir == "" { + tempDir = os.TempDir() + } + + dir := filepath.Join(tempDir, integrationsDir) // Create integrations Storer directory if os.MkdirAll(dir, dirFilePerm) != nil { - dir = os.TempDir() + dir = tempDir } return dir }