github.com/koko1123/flow-go-1@v0.29.6/tools/test_monitor/common/utility.go (about)

     1  // Package common has helper / utility functions used by all levels of flaky test monitor.
     2  package common
     3  
     4  import (
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"io/fs"
    10  	"os"
    11  	"reflect"
    12  	"strconv"
    13  	"time"
    14  )
    15  
    16  // AssertNoError checks that the passed in error is nil and panics
    17  // with the supplied message if that's not the case.
    18  // Useful helper to eliminate the need to keep checking for errors.
    19  func AssertNoError(err error, panicMessage string) {
    20  	if err != nil {
    21  		panic(panicMessage + ": " + err.Error())
    22  	}
    23  }
    24  
    25  // ConvertToNDecimalPlaces2 converts the supplied numerator and denominator fraction into
    26  // a decimal with n decimal places. Works the same way as ConvertToNDecimalPlaces()
    27  // but has a float for the numerator.
    28  func ConvertToNDecimalPlaces2(n int, numerator float64, denominator int) float64 {
    29  	return convertToNDecimalPlacesInternal(n, numerator, float64(denominator))
    30  }
    31  
    32  // ConvertToNDecimalPlaces converts the supplied numerator and denominator fraction into
    33  // a decimal with n decimal places.
    34  func ConvertToNDecimalPlaces(n int, numerator, denominator int) float64 {
    35  	return convertToNDecimalPlacesInternal(n, float64(numerator), float64(denominator))
    36  }
    37  
    38  func convertToNDecimalPlacesInternal(n int, numerator, denominator float64) float64 {
    39  	if numerator == 0 || denominator == 0 {
    40  		return 0
    41  	}
    42  	formatSpecifier := "%." + fmt.Sprint(n) + "f"
    43  	ratioString := fmt.Sprintf(formatSpecifier, numerator/denominator)
    44  	ratioFloat, err := strconv.ParseFloat(ratioString, 32)
    45  	AssertNoError(err, "failure parsing string to float")
    46  	return float64(ratioFloat)
    47  }
    48  
    49  func GetCommitSha() string {
    50  	commitSha := os.Getenv("COMMIT_SHA")
    51  	if commitSha == "" {
    52  		panic("COMMIT_SHA can't be empty")
    53  	}
    54  	return commitSha
    55  }
    56  
    57  func GetRunID() string {
    58  	runID := os.Getenv("RUN_ID")
    59  	if runID == "" {
    60  		panic("RUN_ID can't be empty")
    61  	}
    62  	return runID
    63  }
    64  
    65  func GetCommitDate() time.Time {
    66  	commitDate, err := time.Parse(time.RFC3339, os.Getenv("COMMIT_DATE"))
    67  	AssertNoError(err, "error parsing COMMIT_DATE")
    68  	return commitDate
    69  }
    70  
    71  func GetJobRunDate() time.Time {
    72  	jobStarted, err := time.Parse(time.RFC3339, os.Getenv("JOB_STARTED"))
    73  	AssertNoError(err, "error parsing JOB_STARTED")
    74  	return jobStarted
    75  }
    76  
    77  // IsDirEmpty checks if directory is empty (has no files) and return true if it's empty, false otherwise.
    78  // Useful for determining whether to delete the failures / exceptions directories
    79  // for cases when there were no failures / exceptions.
    80  // From https://stackoverflow.com/a/30708914/5719544.
    81  func IsDirEmpty(name string) bool {
    82  	f, err := os.Open(name)
    83  	AssertNoError(err, "error reading directory")
    84  
    85  	defer f.Close()
    86  
    87  	_, err = f.Readdirnames(1)
    88  	if err == io.EOF {
    89  		return true
    90  	}
    91  	AssertNoError(err, "error reading dir contents")
    92  	return false
    93  }
    94  
    95  // DirExists checks if directory exists and return true if it does, false otherwise.
    96  func DirExists(path string) bool {
    97  	_, err := os.Stat(path)
    98  
    99  	// directory exists if there is no error
   100  	if err == nil {
   101  		return true
   102  	}
   103  
   104  	// directory doesn't exist if error is of specific type
   105  	if errors.Is(err, fs.ErrNotExist) {
   106  		return false
   107  	}
   108  
   109  	// should never get to here
   110  	panic("error checking if directory exists:" + err.Error())
   111  }
   112  
   113  // SaveToFile save test run/summary to local JSON file.
   114  func SaveToFile(fileName string, testSummary interface{}) {
   115  	testSummaryBytes, err := json.MarshalIndent(testSummary, "", "  ")
   116  	AssertNoError(err, "error marshalling json")
   117  
   118  	file, err := os.Create(fileName)
   119  	AssertNoError(err, "error creating "+fileName)
   120  	defer file.Close()
   121  
   122  	_, err = file.Write(testSummaryBytes)
   123  	AssertNoError(err, "error saving test summary to file")
   124  }
   125  
   126  func SaveLinesToFile(fileName string, list interface{}) {
   127  	sliceType := reflect.TypeOf(list)
   128  	if sliceType.Kind() != reflect.Slice && sliceType.Kind() != reflect.Array {
   129  		panic("argument must be an array or slice")
   130  	}
   131  
   132  	file, err := os.Create(fileName)
   133  	AssertNoError(err, "error creating "+fileName)
   134  	defer file.Close()
   135  
   136  	l := reflect.ValueOf(list)
   137  	for i := 0; i < l.Len(); i++ {
   138  		b, err := json.Marshal(l.Index(i).Interface())
   139  		AssertNoError(err, "error marshalling json")
   140  
   141  		_, err = file.Write(b)
   142  		AssertNoError(err, "error writing line to file")
   143  
   144  		_, err = file.Write([]byte("\n"))
   145  		AssertNoError(err, "error writing newline")
   146  	}
   147  }