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 }