diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index 1e506cdd..2721c9c0 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -44,7 +44,7 @@ blocks: - 'shellcheck sem-service -f gcc | wc -l && [[ "$(shellcheck sem-service -f gcc | wc -l)" -le 76 ]]' - 'shellcheck sem-version -f gcc | wc -l && [[ "$(shellcheck sem-version -f gcc | wc -l)" -le 21 ]]' - 'shellcheck cache -f gcc | wc -l && [[ "$(shellcheck cache -f gcc | wc -l)" -le 152 ]]' - - 'shellcheck libcheckout -f gcc | wc -l && [[ "$(shellcheck libcheckout -f gcc | wc -l)" -le 89 ]]' + - 'shellcheck libcheckout -f gcc | wc -l && [[ "$(shellcheck libcheckout -f gcc | wc -l)" -le 85 ]]' - shellcheck install-package - name: Sem Version Tests bionic diff --git a/cache-cli/cmd/restore.go b/cache-cli/cmd/restore.go index c81cd9ab..51043db8 100644 --- a/cache-cli/cmd/restore.go +++ b/cache-cli/cmd/restore.go @@ -2,11 +2,13 @@ package cmd import ( "fmt" + "io/fs" "os" "strings" "time" "github.com/semaphoreci/toolbox/cache-cli/pkg/files" + "github.com/semaphoreci/toolbox/cache-cli/pkg/metrics" "github.com/semaphoreci/toolbox/cache-cli/pkg/storage" "github.com/semaphoreci/toolbox/cache-cli/pkg/utils" "github.com/spf13/cobra" @@ -32,6 +34,9 @@ func RunRestore(cmd *cobra.Command, args []string) { storage, err := storage.InitStorage() utils.Check(err) + metricsManager, err := metrics.InitMetricsManager(metrics.LocalBackend) + utils.Check(err) + if len(args) == 0 { lookupResults := files.Lookup(files.LookupOptions{ GitBranch: os.Getenv("SEMAPHORE_GIT_BRANCH"), @@ -47,21 +52,21 @@ func RunRestore(cmd *cobra.Command, args []string) { fmt.Printf("Detected %s.\n", lookupResult.DetectedFile) for _, entry := range lookupResult.Entries { fmt.Printf("Fetching '%s' directory with cache keys '%s'...\n", entry.Path, strings.Join(entry.Keys, ",")) - downloadAndUnpack(storage, entry.Keys) + downloadAndUnpack(storage, metricsManager, entry.Keys) } } } else { keys := strings.Split(args[0], ",") - downloadAndUnpack(storage, keys) + downloadAndUnpack(storage, metricsManager, keys) } } -func downloadAndUnpack(storage storage.Storage, keys []string) { +func downloadAndUnpack(storage storage.Storage, metricsManager metrics.MetricsManager, keys []string) { for _, rawKey := range keys { key := NormalizeKey(rawKey) if ok, _ := storage.HasKey(key); ok { fmt.Printf("HIT: '%s', using key '%s'.\n", key, key) - downloadAndUnpackKey(storage, key) + downloadAndUnpackKey(storage, metricsManager, key) break } @@ -71,7 +76,7 @@ func downloadAndUnpack(storage storage.Storage, keys []string) { matchingKey := findMatchingKey(availableKeys, key) if matchingKey != "" { fmt.Printf("HIT: '%s', using key '%s'.\n", key, matchingKey) - downloadAndUnpackKey(storage, matchingKey) + downloadAndUnpackKey(storage, metricsManager, matchingKey) break } else { fmt.Printf("MISS: '%s'.\n", key) @@ -89,7 +94,7 @@ func findMatchingKey(availableKeys []storage.CacheKey, match string) string { return "" } -func downloadAndUnpackKey(storage storage.Storage, key string) { +func downloadAndUnpackKey(storage storage.Storage, metricsManager metrics.MetricsManager, key string) { downloadStart := time.Now() fmt.Printf("Downloading key '%s'...\n", key) compressed, err := storage.Restore(key) @@ -97,11 +102,13 @@ func downloadAndUnpackKey(storage storage.Storage, key string) { downloadDuration := time.Since(downloadStart) info, _ := os.Stat(compressed.Name()) + fmt.Printf("Download complete. Duration: %v. Size: %v bytes.\n", downloadDuration.String(), files.HumanReadableSize(info.Size())) + publishMetrics(metricsManager, info, downloadDuration) unpackStart := time.Now() fmt.Printf("Unpacking '%s'...\n", compressed.Name()) - restorationPath, err := files.Unpack(compressed.Name()) + restorationPath, err := files.Unpack(metricsManager, compressed.Name()) utils.Check(err) unpackDuration := time.Since(unpackStart) @@ -110,6 +117,41 @@ func downloadAndUnpackKey(storage storage.Storage, key string) { os.Remove(compressed.Name()) } +func publishMetrics(metricsManager metrics.MetricsManager, fileInfo fs.FileInfo, downloadDuration time.Duration) error { + metricsToPublish := []metrics.Metric{ + {Name: metrics.CacheDownloadSize, Value: fmt.Sprintf("%d", fileInfo.Size())}, + {Name: metrics.CacheDownloadTime, Value: downloadDuration.String()}, + } + + username := os.Getenv("SEMAPHORE_CACHE_USERNAME") + if username != "" { + metricsToPublish = append(metricsToPublish, metrics.Metric{Name: metrics.CacheUser, Value: username}) + } + + cacheServerIP := getCacheServerIP() + if cacheServerIP != "" { + metricsToPublish = append(metricsToPublish, metrics.Metric{Name: metrics.CacheServer, Value: cacheServerIP}) + } + + metricsToPublish = append(metricsToPublish, metrics.Metric{Name: metrics.CacheTotalRate, Value: "1"}) + + return metricsManager.PublishBatch(metricsToPublish) +} + +func getCacheServerIP() string { + cacheURL := os.Getenv("SEMAPHORE_CACHE_URL") + if cacheURL != "" { + ipAndPort := strings.Split(cacheURL, ":") + if len(ipAndPort) != 2 { + return "" + } + + return ipAndPort[0] + } + + return "" +} + func init() { RootCmd.AddCommand(restoreCmd) } diff --git a/cache-cli/pkg/files/compress_test.go b/cache-cli/pkg/files/compress_test.go index 5c92a9ad..509996cf 100644 --- a/cache-cli/pkg/files/compress_test.go +++ b/cache-cli/pkg/files/compress_test.go @@ -8,10 +8,14 @@ import ( "strings" "testing" + "github.com/semaphoreci/toolbox/cache-cli/pkg/metrics" assert "github.com/stretchr/testify/assert" ) func Test__CompressAndUnpack(t *testing.T) { + metricsManager, err := metrics.InitMetricsManager(metrics.LocalBackend) + assert.Nil(t, err) + t.Run("file to compress is not present", func(t *testing.T) { compressedFileName, err := Compress("abc0001", "/tmp/this-file-does-not-exist") assert.NotNil(t, err) @@ -19,14 +23,14 @@ func Test__CompressAndUnpack(t *testing.T) { }) t.Run("file to unpack is not present", func(t *testing.T) { - _, err := Unpack("/tmp/this-file-does-not-exist") + _, err := Unpack(metricsManager, "/tmp/this-file-does-not-exist") assert.NotNil(t, err) }) t.Run("using absolute paths", func(t *testing.T) { tempDir, _ := ioutil.TempDir("/tmp", "*") tempFile, _ := ioutil.TempFile(tempDir, "*") - assertCompressAndUnpack(t, tempDir, tempFile.Name()) + assertCompressAndUnpack(t, metricsManager, tempDir, tempFile.Name()) }) t.Run("using relative paths", func(t *testing.T) { @@ -34,7 +38,7 @@ func Test__CompressAndUnpack(t *testing.T) { tempDir, _ := ioutil.TempDir(cwd, "*") tempFile, _ := ioutil.TempFile(tempDir, "*") tempDirBase := filepath.Base(tempDir) - assertCompressAndUnpack(t, tempDirBase, tempFile.Name()) + assertCompressAndUnpack(t, metricsManager, tempDirBase, tempFile.Name()) }) t.Run("using single file", func(t *testing.T) { @@ -53,7 +57,7 @@ func Test__CompressAndUnpack(t *testing.T) { assert.Nil(t, err) // unpacking - unpackedAt, err := Unpack(compressedFileName) + unpackedAt, err := Unpack(metricsManager, compressedFileName) assert.Nil(t, err) assert.Equal(t, tempFile.Name(), unpackedAt) @@ -67,7 +71,7 @@ func Test__CompressAndUnpack(t *testing.T) { }) } -func assertCompressAndUnpack(t *testing.T, tempDirectory, tempFile string) { +func assertCompressAndUnpack(t *testing.T, metricsManager metrics.MetricsManager, tempDirectory, tempFile string) { // compressing compressedFileName, err := Compress("abc0003", tempDirectory) assert.Nil(t, err) @@ -82,7 +86,7 @@ func assertCompressAndUnpack(t *testing.T, tempDirectory, tempFile string) { assert.Nil(t, err) // unpacking - unpackedAt, err := Unpack(compressedFileName) + unpackedAt, err := Unpack(metricsManager, compressedFileName) assert.Nil(t, err) assert.Equal(t, fmt.Sprintf("%s/", tempDirectory), unpackedAt) diff --git a/cache-cli/pkg/files/unpack.go b/cache-cli/pkg/files/unpack.go index f9aa8eb0..222a7cea 100644 --- a/cache-cli/pkg/files/unpack.go +++ b/cache-cli/pkg/files/unpack.go @@ -8,33 +8,33 @@ import ( "os" "os/exec" "path/filepath" + + "github.com/semaphoreci/toolbox/cache-cli/pkg/metrics" ) -func Unpack(path string) (string, error) { +func Unpack(metricsManager metrics.MetricsManager, path string) (string, error) { restorationPath, err := findRestorationPath(path) if err != nil { + metricsManager.Publish(metrics.Metric{Name: metrics.CacheCorruptionRate, Value: "1"}) return "", err } - cmd, err := unpackCommand(restorationPath, path) - if err != nil { - return "", err - } - + cmd := unpackCommand(restorationPath, path) _, err = cmd.Output() if err != nil { + metricsManager.Publish(metrics.Metric{Name: metrics.CacheCorruptionRate, Value: "1"}) return "", err } return restorationPath, nil } -func unpackCommand(restorationPath, tempFile string) (*exec.Cmd, error) { +func unpackCommand(restorationPath, tempFile string) *exec.Cmd { if filepath.IsAbs(restorationPath) { - return exec.Command("tar", "xzPf", tempFile, "-C", "."), nil + return exec.Command("tar", "xzPf", tempFile, "-C", ".") } - return exec.Command("tar", "xzf", tempFile, "-C", "."), nil + return exec.Command("tar", "xzf", tempFile, "-C", ".") } func findRestorationPath(path string) (string, error) { diff --git a/cache-cli/pkg/files/unpack_test.go b/cache-cli/pkg/files/unpack_test.go new file mode 100644 index 00000000..1019f20d --- /dev/null +++ b/cache-cli/pkg/files/unpack_test.go @@ -0,0 +1,30 @@ +package files + +import ( + "fmt" + "io/ioutil" + "os" + "testing" + + "github.com/semaphoreci/toolbox/cache-cli/pkg/metrics" + assert "github.com/stretchr/testify/assert" +) + +func Test__UnpackSendsMetricsOnFailure(t *testing.T) { + os.Setenv("SEMAPHORE_TOOLBOX_METRICS_ENABLED", "true") + metricsManager, err := metrics.InitMetricsManager(metrics.LocalBackend) + assert.Nil(t, err) + + tempFile, _ := ioutil.TempFile("/tmp", "*") + tempFile.WriteString("this is not a proper archive") + + _, err = Unpack(metricsManager, tempFile.Name()) + assert.NotNil(t, err) + + bytes, err := ioutil.ReadFile("/tmp/toolbox_metrics") + assert.Nil(t, err) + assert.Contains(t, string(bytes), fmt.Sprintf("%s 1", metrics.CacheCorruptionRate)) + + os.Remove(tempFile.Name()) + os.Remove("/tmp/toolbox_metrics") +} diff --git a/cache-cli/pkg/metrics/local.go b/cache-cli/pkg/metrics/local.go new file mode 100644 index 00000000..712fbf63 --- /dev/null +++ b/cache-cli/pkg/metrics/local.go @@ -0,0 +1,67 @@ +package metrics + +import ( + "fmt" + "os" +) + +type LocalMetricsManager struct { + ToolboxMetricsPath string + CacheMetricsPath string +} + +func NewLocalMetricsBackend() (*LocalMetricsManager, error) { + return &LocalMetricsManager{ + ToolboxMetricsPath: "/tmp/toolbox_metrics", + CacheMetricsPath: "/tmp/cache_metrics", + }, nil +} + +func (b *LocalMetricsManager) Enabled() bool { + return os.Getenv("SEMAPHORE_TOOLBOX_METRICS_ENABLED") == "true" +} + +func (b *LocalMetricsManager) PublishBatch(metrics []Metric) error { + if !b.Enabled() { + return nil + } + + for _, metric := range metrics { + err := b.Publish(metric) + if err != nil { + return err + } + } + + return nil +} + +func (b *LocalMetricsManager) Publish(metric Metric) error { + if !b.Enabled() { + return nil + } + + switch metric.Name { + case CacheDownloadSize, CacheDownloadTime, CacheUser, CacheServer: + return publishMetricToFile(b.CacheMetricsPath, metric.Name, metric.Value) + case CacheTotalRate, CacheCorruptionRate: + return publishMetricToFile(b.ToolboxMetricsPath, metric.Name, metric.Value) + } + + fmt.Printf("Ignoring metric %s\n", metric.Name) + return nil +} + +func publishMetricToFile(file, metricName, metricValue string) error { + f, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + return err + } + + defer f.Close() + + line := fmt.Sprintf("%s %s\n", metricName, metricValue) + + _, err = f.WriteString(line) + return err +} diff --git a/cache-cli/pkg/metrics/local_test.go b/cache-cli/pkg/metrics/local_test.go new file mode 100644 index 00000000..bedd6e1e --- /dev/null +++ b/cache-cli/pkg/metrics/local_test.go @@ -0,0 +1,96 @@ +package metrics + +import ( + "fmt" + "io/ioutil" + "os" + "testing" + + assert "github.com/stretchr/testify/assert" +) + +func Test__Publish(t *testing.T) { + os.Setenv("SEMAPHORE_TOOLBOX_METRICS_ENABLED", "true") + metricsManager, err := NewLocalMetricsBackend() + assert.Nil(t, err) + + t.Run("valid cache metrics", func(t *testing.T) { + err = metricsManager.PublishBatch([]Metric{ + {Name: CacheDownloadSize, Value: "1000"}, + {Name: CacheDownloadTime, Value: "30"}, + {Name: CacheUser, Value: "tester"}, + {Name: CacheServer, Value: "0.0.0.0"}, + }) + + assert.Nil(t, err) + + bytes, err := ioutil.ReadFile(metricsManager.CacheMetricsPath) + assert.Nil(t, err) + + assert.Contains(t, string(bytes), fmt.Sprintf("%s 1000", CacheDownloadSize)) + assert.Contains(t, string(bytes), fmt.Sprintf("%s 30", CacheDownloadTime)) + assert.Contains(t, string(bytes), fmt.Sprintf("%s tester", CacheUser)) + assert.Contains(t, string(bytes), fmt.Sprintf("%s 0.0.0.0", CacheServer)) + + _, err = os.Stat(metricsManager.ToolboxMetricsPath) + assert.NotNil(t, err) + + os.Remove(metricsManager.CacheMetricsPath) + }) + + t.Run("valid toolbox metrics", func(t *testing.T) { + err = metricsManager.PublishBatch([]Metric{ + {Name: CacheTotalRate, Value: "1"}, + {Name: CacheCorruptionRate, Value: "1"}, + }) + + assert.Nil(t, err) + + bytes, err := ioutil.ReadFile(metricsManager.ToolboxMetricsPath) + assert.Nil(t, err) + + assert.Contains(t, string(bytes), fmt.Sprintf("%s 1", CacheTotalRate)) + assert.Contains(t, string(bytes), fmt.Sprintf("%s 1", CacheCorruptionRate)) + + _, err = os.Stat(metricsManager.CacheMetricsPath) + assert.NotNil(t, err) + + os.Remove(metricsManager.ToolboxMetricsPath) + }) + + t.Run("invalid metrics are ignored", func(t *testing.T) { + err = metricsManager.PublishBatch([]Metric{ + {Name: "some-invalid-metric-name", Value: "invalid"}, + }) + + assert.Nil(t, err) + + _, err = os.Stat(metricsManager.CacheMetricsPath) + assert.NotNil(t, err) + + _, err = os.Stat(metricsManager.ToolboxMetricsPath) + assert.NotNil(t, err) + }) + + t.Run("ignores metrics if it is not enabled", func(t *testing.T) { + os.Setenv("SEMAPHORE_TOOLBOX_METRICS_ENABLED", "false") + + err = metricsManager.PublishBatch([]Metric{ + {Name: CacheDownloadSize, Value: "1000"}, + {Name: CacheDownloadTime, Value: "30"}, + {Name: CacheUser, Value: "tester"}, + {Name: CacheServer, Value: "0.0.0.0"}, + {Name: CacheTotalRate, Value: "1"}, + {Name: CacheCorruptionRate, Value: "1"}, + {Name: "some-invalid-metric-name", Value: "invalid"}, + }) + + assert.Nil(t, err) + + _, err = os.Stat(metricsManager.CacheMetricsPath) + assert.NotNil(t, err) + + _, err = os.Stat(metricsManager.ToolboxMetricsPath) + assert.NotNil(t, err) + }) +} diff --git a/cache-cli/pkg/metrics/metrics.go b/cache-cli/pkg/metrics/metrics.go new file mode 100644 index 00000000..a80c3e42 --- /dev/null +++ b/cache-cli/pkg/metrics/metrics.go @@ -0,0 +1,31 @@ +package metrics + +import "fmt" + +const LocalBackend = "local" +const CacheDownloadSize = "cache_download_size" +const CacheDownloadTime = "cache_download_time" +const CacheUser = "cache_user" +const CacheServer = "cache_server" +const CacheTotalRate = "cache_total_rate" +const CacheCorruptionRate = "cache_corruption_rate" + +type MetricsManager interface { + Enabled() bool + Publish(metric Metric) error + PublishBatch(metrics []Metric) error +} + +type Metric struct { + Name string + Value string +} + +func InitMetricsManager(backend string) (MetricsManager, error) { + switch backend { + case LocalBackend: + return NewLocalMetricsBackend() + default: + return nil, fmt.Errorf("metrics backend '%s' is not available", backend) + } +} diff --git a/libcheckout b/libcheckout index aea5fe78..3eecbd99 100755 --- a/libcheckout +++ b/libcheckout @@ -69,8 +69,7 @@ function checkout::reset_to_sha { checkout::checkrevision if [ "$?" -eq "0" ]; then git reset --hard $SEMAPHORE_GIT_SHA 2>/dev/null - echo "libcheckout_repo_size $(du -s . | awk {'print $1'})" >> /tmp/toolbox_metrics - + checkout::metric "$(du -s . | awk '{ print $1 }')" return 0 else return 1 @@ -95,7 +94,7 @@ function checkout::switch_revision() { return 1 else - echo "libcheckout_repo_size $(du -s . | awk {'print $1'})" >> /tmp/toolbox_metrics + checkout::metric "$(du -s . | awk '{ print $1 }')" echo "HEAD is now at ${SEMAPHORE_GIT_SHA} Release ${SEMAPHORE_GIT_TAG_NAME}" return 0 @@ -196,7 +195,8 @@ function checkout::shallow() { fi fi fi - echo "libcheckout_repo_size $(du -s . | awk {'print $1'})" >> /tmp/toolbox_metrics + + checkout::metric "$(du -s . | awk '{ print $1 }')" } function checkout::refbased() { @@ -238,4 +238,10 @@ function checkout::refbased() { checkout::shallow } +function checkout::metric() { + if [[ "$SEMAPHORE_TOOLBOX_METRICS_ENABLED" == "true" ]]; then + echo "libcheckout_repo_size $1" >> /tmp/toolbox_metrics + fi +} + export -f checkout diff --git a/tests/cache.bats b/tests/cache.bats index 3248b379..b03b85bd 100644 --- a/tests/cache.bats +++ b/tests/cache.bats @@ -9,6 +9,8 @@ teardown() { cache delete bats-test-$SEMAPHORE_GIT_BRANCH cache delete bats-test-$SEMAPHORE_GIT_BRANCH-1 unset CACHE_SIZE + rm -rf /tmp/toolbox_metrics + rm -rf /tmp/cache_metrics } normalize_key() { @@ -266,6 +268,25 @@ normalize_key() { refute_output --partial "command not found" } +@test "populates metrics file" { + export SEMAPHORE_TOOLBOX_METRICS_ENABLED=true + test_key_1=$(normalize_key bats-test-$SEMAPHORE_GIT_BRANCH) + mkdir tmp && touch tmp/example.file + cache store $test_key_1 tmp + rm -rf tmp + cache restore $test_key_1 + + export SEMAPHORE_CACHE_IP=$(echo "$SEMAPHORE_CACHE_URL" | awk -F ":" '{print $1}') + run cat /tmp/cache_metrics + assert_line --partial "cache_download_size" + assert_line --partial "cache_download_time" + assert_line "cache_user $SEMAPHORE_CACHE_USERNAME" + assert_line "cache_server $SEMAPHORE_CACHE_IP" + + run cat /tmp/toolbox_metrics + assert_line "cache_total_rate 1" +} + @test "restoring nonexistent directory from cache" { run cache has_key test-12123 assert_failure @@ -280,7 +301,6 @@ normalize_key() { @test "restoring corrupted archive from cache" { echo "not a proper cache archive" | dd of=corrupted-file - export SEMAPHORE_CACHE_IP=$(echo "$SEMAPHORE_CACHE_URL" | awk -F ":" '{print $1}') export SEMAPHORE_CACHE_PORT=$(echo "$SEMAPHORE_CACHE_URL" | awk -F ":" '{print $2}') @@ -298,6 +318,31 @@ normalize_key() { rm -f corrupted-file export CACHE_FAIL_ON_ERROR=false + cache clear +} + +@test "publishes metrics when restoring corrupted archive from cache" { + export SEMAPHORE_TOOLBOX_METRICS_ENABLED=true + echo "not a proper cache archive" | dd of=corrupted-file + export SEMAPHORE_CACHE_IP=$(echo "$SEMAPHORE_CACHE_URL" | awk -F ":" '{print $1}') + export SEMAPHORE_CACHE_PORT=$(echo "$SEMAPHORE_CACHE_URL" | awk -F ":" '{print $2}') + + sftp \ + -i $SEMAPHORE_CACHE_PRIVATE_KEY_PATH \ + -P $SEMAPHORE_CACHE_PORT \ + $SEMAPHORE_CACHE_USERNAME@$SEMAPHORE_CACHE_IP:. <<< $'put corrupted-file' + + cache restore corrupted-file + + run cat /tmp/cache_metrics + assert_line --partial "cache_download_size" + assert_line --partial "cache_download_time" + assert_line "cache_user $SEMAPHORE_CACHE_USERNAME" + assert_line "cache_server $SEMAPHORE_CACHE_IP" + + run cat /tmp/toolbox_metrics + assert_line "cache_total_rate 1" + assert_line "cache_corruption_rate 1" } @test "fallback key option" { diff --git a/tests/libcheckout.bats b/tests/libcheckout.bats index 8fdbdf17..b346eb52 100644 --- a/tests/libcheckout.bats +++ b/tests/libcheckout.bats @@ -23,6 +23,7 @@ setup() { teardown() { rm -rf $SEMAPHORE_GIT_DIR + rm -rf /tmp/toolbox_metrics } # Push @@ -263,3 +264,24 @@ teardown() { assert_failure assert_output --partial "Revision: $SEMAPHORE_GIT_SHA not found" } + +@test "libcheckout - populates metrics file if hosted environment" { + export SEMAPHORE_GIT_REF_TYPE="push" + export SEMAPHORE_GIT_SHA=91940c2cc18ec08b751482f806f1b8bfa03d98a5 + export SEMAPHORE_TOOLBOX_METRICS_ENABLED=true + checkout + + run cat /tmp/toolbox_metrics + assert_line --partial "libcheckout_repo_size" +} + +@test "libcheckout - does not populate metrics file if self-hosted environment" { + export SEMAPHORE_GIT_REF_TYPE="push" + export SEMAPHORE_GIT_SHA=91940c2cc18ec08b751482f806f1b8bfa03d98a5 + export SEMAPHORE_TOOLBOX_METRICS_ENABLED=false + checkout + + run cat /tmp/toolbox_metrics + assert_failure + assert_line "cat: /tmp/toolbox_metrics: No such file or directory" +} \ No newline at end of file diff --git a/tests/macOS_cache.bats b/tests/macOS_cache.bats index 96c3e0f3..a1438203 100644 --- a/tests/macOS_cache.bats +++ b/tests/macOS_cache.bats @@ -9,6 +9,8 @@ teardown() { cache delete bats-test-$SEMAPHORE_GIT_BRANCH cache delete bats-test-$SEMAPHORE_GIT_BRANCH-1 unset CACHE_SIZE + rm -rf /tmp/toolbox_metrics + rm -rf /tmp/cache_metrics } normalize_key() { @@ -276,7 +278,27 @@ normalize_key() { refute_output --partial "command not found" } -@test "restoring corrupted archive from cache" { +@test "[macOS] populates metrics file" { + export SEMAPHORE_TOOLBOX_METRICS_ENABLED=true + test_key_1=$(normalize_key bats-test-$SEMAPHORE_GIT_BRANCH) + mkdir tmp && touch tmp/example.file + cache store $test_key_1 tmp + rm -rf tmp + cache restore $test_key_1 + + export SEMAPHORE_CACHE_IP=$(echo "$SEMAPHORE_CACHE_URL" | awk -F ":" '{print $1}') + + run cat /tmp/cache_metrics + assert_line --partial "cache_download_size" + assert_line --partial "cache_download_time" + assert_line "cache_user $SEMAPHORE_CACHE_USERNAME" + assert_line "cache_server $SEMAPHORE_CACHE_IP" + + run cat /tmp/toolbox_metrics + assert_line "cache_total_rate 1" +} + +@test "[macOS] restoring corrupted archive from cache" { echo "not a proper cache archive" | dd of=corrupted-file export SEMAPHORE_CACHE_IP=$(echo "$SEMAPHORE_CACHE_URL" | awk -F ":" '{print $1}') @@ -298,6 +320,32 @@ normalize_key() { export CACHE_FAIL_ON_ERROR=false } +@test "[macOS] publishes metrics when restoring corrupted archive from cache" { + export SEMAPHORE_TOOLBOX_METRICS_ENABLED=true + + echo "not a proper cache archive" | dd of=corrupted-file + + export SEMAPHORE_CACHE_IP=$(echo "$SEMAPHORE_CACHE_URL" | awk -F ":" '{print $1}') + export SEMAPHORE_CACHE_PORT=$(echo "$SEMAPHORE_CACHE_URL" | awk -F ":" '{print $2}') + + sftp \ + -i $SEMAPHORE_CACHE_PRIVATE_KEY_PATH \ + -P $SEMAPHORE_CACHE_PORT \ + $SEMAPHORE_CACHE_USERNAME@$SEMAPHORE_CACHE_IP:. <<< $'put corrupted-file' + + cache restore corrupted-file + + run cat /tmp/cache_metrics + assert_line --partial "cache_download_size" + assert_line --partial "cache_download_time" + assert_line "cache_user $SEMAPHORE_CACHE_USERNAME" + assert_line "cache_server $SEMAPHORE_CACHE_IP" + + run cat /tmp/toolbox_metrics + assert_line "cache_total_rate 1" + assert_line "cache_corruption_rate 1" +} + @test "[macOS] fallback key option" { touch tmp.file test_key_1=$(normalize_key bats-test-$SEMAPHORE_GIT_BRANCH)