mirror of
				https://github.com/prometheus/prometheus.git
				synced 2025-10-31 08:21:16 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			167 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2013 The Prometheus Authors
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| // http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| package testutil
 | |
| 
 | |
| import (
 | |
| 	"crypto/sha256"
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strconv"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/stretchr/testify/require"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// The base directory used for test emissions, which instructs the operating
 | |
| 	// system to use the default temporary directory as the base or TMPDIR
 | |
| 	// environment variable.
 | |
| 	defaultDirectory = ""
 | |
| 
 | |
| 	// NilCloser is a no-op Closer.
 | |
| 	NilCloser = nilCloser(true)
 | |
| 
 | |
| 	// The number of times that a TemporaryDirectory will retry its removal
 | |
| 	temporaryDirectoryRemoveRetries = 2
 | |
| )
 | |
| 
 | |
| type (
 | |
| 	// Closer is the interface that wraps the Close method.
 | |
| 	Closer interface {
 | |
| 		// Close reaps the underlying directory and its children. The directory
 | |
| 		// could be deleted by its users already.
 | |
| 		Close()
 | |
| 	}
 | |
| 
 | |
| 	nilCloser bool
 | |
| 
 | |
| 	// TemporaryDirectory models a closeable path for transient POSIX disk
 | |
| 	// activities.
 | |
| 	TemporaryDirectory interface {
 | |
| 		Closer
 | |
| 
 | |
| 		// Path returns the underlying path for access.
 | |
| 		Path() string
 | |
| 	}
 | |
| 
 | |
| 	// temporaryDirectory is kept as a private type due to private fields and
 | |
| 	// their interactions.
 | |
| 	temporaryDirectory struct {
 | |
| 		path   string
 | |
| 		tester T
 | |
| 	}
 | |
| 
 | |
| 	callbackCloser struct {
 | |
| 		fn func()
 | |
| 	}
 | |
| 
 | |
| 	// T implements the needed methods of testing.TB so that we do not need
 | |
| 	// to actually import testing (which has the side effect of adding all
 | |
| 	// the test flags, which we do not want in non-test binaries even if
 | |
| 	// they make use of these utilities for some reason).
 | |
| 	T interface {
 | |
| 		Errorf(format string, args ...interface{})
 | |
| 		FailNow()
 | |
| 	}
 | |
| )
 | |
| 
 | |
| func (c nilCloser) Close() {
 | |
| }
 | |
| 
 | |
| func (c callbackCloser) Close() {
 | |
| 	c.fn()
 | |
| }
 | |
| 
 | |
| // NewCallbackCloser returns a Closer that calls the provided function upon
 | |
| // closing.
 | |
| func NewCallbackCloser(fn func()) Closer {
 | |
| 	return &callbackCloser{
 | |
| 		fn: fn,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (t temporaryDirectory) Close() {
 | |
| 	retries := temporaryDirectoryRemoveRetries
 | |
| 	err := os.RemoveAll(t.path)
 | |
| 	for err != nil && retries > 0 {
 | |
| 		switch {
 | |
| 		case os.IsNotExist(err):
 | |
| 			err = nil
 | |
| 		default:
 | |
| 			retries--
 | |
| 			err = os.RemoveAll(t.path)
 | |
| 		}
 | |
| 	}
 | |
| 	require.NoError(t.tester, err)
 | |
| }
 | |
| 
 | |
| func (t temporaryDirectory) Path() string {
 | |
| 	return t.path
 | |
| }
 | |
| 
 | |
| // NewTemporaryDirectory creates a new temporary directory for transient POSIX
 | |
| // activities.
 | |
| func NewTemporaryDirectory(name string, t T) (handler TemporaryDirectory) {
 | |
| 	var (
 | |
| 		directory string
 | |
| 		err       error
 | |
| 	)
 | |
| 
 | |
| 	directory, err = ioutil.TempDir(defaultDirectory, name)
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	handler = temporaryDirectory{
 | |
| 		path:   directory,
 | |
| 		tester: t,
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // DirHash returns a hash of all files attributes and their content within a directory.
 | |
| func DirHash(t *testing.T, path string) []byte {
 | |
| 	hash := sha256.New()
 | |
| 	err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		if info.IsDir() {
 | |
| 			return nil
 | |
| 		}
 | |
| 		f, err := os.Open(path)
 | |
| 		require.NoError(t, err)
 | |
| 		defer f.Close()
 | |
| 
 | |
| 		_, err = io.Copy(hash, f)
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		_, err = io.WriteString(hash, strconv.Itoa(int(info.Size())))
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		_, err = io.WriteString(hash, info.Name())
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		modTime, err := info.ModTime().GobEncode()
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		_, err = io.WriteString(hash, string(modTime))
 | |
| 		require.NoError(t, err)
 | |
| 		return nil
 | |
| 	})
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	return hash.Sum(nil)
 | |
| }
 |