1// Copyright 2019 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package status 16 17import ( 18 "reflect" 19 "testing" 20 "time" 21) 22 23type testCriticalPath struct { 24 *CriticalPath 25 Counts 26 27 actions map[int]*Action 28} 29 30type testClock time.Time 31 32func (t testClock) Now() time.Time { return time.Time(t) } 33 34func (t *testCriticalPath) start(id int, startTime time.Duration, outputs, inputs []string) { 35 t.clock = testClock(time.Unix(0, 0).Add(startTime)) 36 action := &Action{ 37 Description: outputs[0], 38 Outputs: outputs, 39 Inputs: inputs, 40 } 41 42 t.actions[id] = action 43 t.StartAction(action) 44} 45 46func (t *testCriticalPath) finish(id int, endTime time.Duration) { 47 t.clock = testClock(time.Unix(0, 0).Add(endTime)) 48 t.FinishAction(t.actions[id]) 49} 50 51func TestCriticalPath(t *testing.T) { 52 tests := []struct { 53 name string 54 msgs func(*testCriticalPath) 55 want []string 56 wantTime time.Duration 57 }{ 58 { 59 name: "empty", 60 msgs: func(cp *testCriticalPath) {}, 61 }, 62 { 63 name: "duplicate", 64 msgs: func(cp *testCriticalPath) { 65 cp.start(0, 0, []string{"a"}, nil) 66 cp.start(1, 0, []string{"a"}, nil) 67 cp.finish(0, 1000) 68 cp.finish(0, 2000) 69 }, 70 want: []string{"a"}, 71 wantTime: 1000, 72 }, 73 { 74 name: "linear", 75 // a 76 // | 77 // b 78 // | 79 // c 80 msgs: func(cp *testCriticalPath) { 81 cp.start(0, 0, []string{"a"}, nil) 82 cp.finish(0, 1000) 83 cp.start(1, 1000, []string{"b"}, []string{"a"}) 84 cp.finish(1, 2000) 85 cp.start(2, 3000, []string{"c"}, []string{"b"}) 86 cp.finish(2, 4000) 87 }, 88 want: []string{"c", "b", "a"}, 89 wantTime: 3000, 90 }, 91 { 92 name: "diamond", 93 // a 94 // |\ 95 // b c 96 // |/ 97 // d 98 msgs: func(cp *testCriticalPath) { 99 cp.start(0, 0, []string{"a"}, nil) 100 cp.finish(0, 1000) 101 cp.start(1, 1000, []string{"b"}, []string{"a"}) 102 cp.start(2, 1000, []string{"c"}, []string{"a"}) 103 cp.finish(1, 2000) 104 cp.finish(2, 3000) 105 cp.start(3, 3000, []string{"d"}, []string{"b", "c"}) 106 cp.finish(3, 4000) 107 }, 108 want: []string{"d", "c", "a"}, 109 wantTime: 4000, 110 }, 111 { 112 name: "multiple", 113 // a d 114 // | | 115 // b e 116 // | 117 // c 118 msgs: func(cp *testCriticalPath) { 119 cp.start(0, 0, []string{"a"}, nil) 120 cp.start(3, 0, []string{"d"}, nil) 121 cp.finish(0, 1000) 122 cp.finish(3, 1000) 123 cp.start(1, 1000, []string{"b"}, []string{"a"}) 124 cp.start(4, 1000, []string{"e"}, []string{"d"}) 125 cp.finish(1, 2000) 126 cp.start(2, 2000, []string{"c"}, []string{"b"}) 127 cp.finish(2, 3000) 128 cp.finish(4, 4000) 129 130 }, 131 want: []string{"e", "d"}, 132 wantTime: 4000, 133 }, 134 } 135 for _, tt := range tests { 136 t.Run(tt.name, func(t *testing.T) { 137 cp := &testCriticalPath{ 138 CriticalPath: NewCriticalPath(), 139 actions: make(map[int]*Action), 140 } 141 142 tt.msgs(cp) 143 144 criticalPath, _, _ := cp.CriticalPath.criticalPath() 145 146 var descs []string 147 for _, x := range criticalPath { 148 descs = append(descs, x.action.Description) 149 } 150 151 if !reflect.DeepEqual(descs, tt.want) { 152 t.Errorf("criticalPath.criticalPath() = %v, want %v", descs, tt.want) 153 } 154 155 var gotTime time.Duration 156 if len(criticalPath) > 0 { 157 gotTime = criticalPath[0].cumulativeDuration 158 } 159 if gotTime != tt.wantTime { 160 t.Errorf("cumulativeDuration[0].cumulativeDuration = %v, want %v", gotTime, tt.wantTime) 161 } 162 }) 163 } 164} 165