github.com/marksheahan/packer@v0.10.2-0.20160613200515-1acb2d6645a0/builder/azure/common/approvals/approvals.go (about)

     1  package approvals
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"runtime"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  type testState struct {
    15  	pc       uintptr
    16  	fullName string
    17  	name     string
    18  	fileName string
    19  	fileLine int
    20  }
    21  
    22  func Verify(t *testing.T, reader io.Reader) error {
    23  	state, err := findTestMethod()
    24  	if err != nil {
    25  		return err
    26  	}
    27  
    28  	return state.compare(state.getApprovalFile(), reader)
    29  }
    30  
    31  func (s *testState) compare(approvalFile string, reader io.Reader) error {
    32  	received, err := ioutil.ReadAll(reader)
    33  	if err != nil {
    34  		return err
    35  	}
    36  
    37  	// Ideally, this should only be written if
    38  	//  1. the approval file does not exist
    39  	//  2. the results differ
    40  	err = s.dumpReceivedTestResult(received)
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	fh, err := os.Open(approvalFile)
    46  	if err != nil {
    47  		return err
    48  	}
    49  	defer fh.Close()
    50  
    51  	approved, err := ioutil.ReadAll(fh)
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	// The two sides are identical, nothing more to do.
    57  	if bytes.Compare(received, approved) == 0 {
    58  		return nil
    59  	}
    60  
    61  	return fmt.Errorf("failed to approved %s", s.name)
    62  }
    63  
    64  func (s *testState) dumpReceivedTestResult(bs []byte) error {
    65  	fn := s.getReceivedFile()
    66  	err := ioutil.WriteFile(fn, bs, 0644)
    67  
    68  	return err
    69  }
    70  
    71  func (s *testState) getReceivedFile() string {
    72  	return fmt.Sprintf("%s.received.txt", s.name)
    73  }
    74  
    75  func (s *testState) getApprovalFile() string {
    76  	return fmt.Sprintf("%s.approved.txt", s.name)
    77  }
    78  
    79  func newTestState(pc uintptr, f *runtime.Func) (*testState, error) {
    80  	state := &testState{
    81  		pc:       pc,
    82  		fullName: f.Name(),
    83  	}
    84  
    85  	state.fileName, state.fileLine = f.FileLine(pc)
    86  
    87  	splits := strings.Split(state.fullName, ".")
    88  	state.name = splits[len(splits)-1]
    89  
    90  	return state, nil
    91  }
    92  
    93  // Walk the call stack, and try to find the test method that was executed.
    94  // The test method is identified by looking for the test runner, which is
    95  // *assumed* to be common across all callers.  The test runner has a Name() of
    96  // 'testing.tRunner'.  The method immediately previous to this is the test
    97  // method.
    98  func findTestMethod() (*testState, error) {
    99  	pc := make([]uintptr, 100)
   100  	count := runtime.Callers(0, pc)
   101  
   102  	i := 0
   103  	var lastFunc *runtime.Func
   104  
   105  	for ; i < count; i++ {
   106  		lastFunc = runtime.FuncForPC(pc[i])
   107  		if isTestRunner(lastFunc) {
   108  			break
   109  		}
   110  	}
   111  
   112  	if i == 0 || !isTestRunner(lastFunc) {
   113  		return nil, fmt.Errorf("approvals: could not find the test method")
   114  	}
   115  
   116  	testMethod := runtime.FuncForPC(pc[i-1])
   117  	return newTestState(pc[i-1], testMethod)
   118  }
   119  
   120  func isTestRunner(f *runtime.Func) bool {
   121  	return f != nil && f.Name() == "testing.tRunner"
   122  }