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, t.Counts) 44} 45 46func (t *testCriticalPath) finish(id int, endTime time.Duration) { 47 t.clock = testClock(time.Unix(0, 0).Add(endTime)) 48 t.FinishAction(ActionResult{ 49 Action: t.actions[id], 50 }, t.Counts) 51} 52 53func TestCriticalPath(t *testing.T) { 54 tests := []struct { 55 name string 56 msgs func(*testCriticalPath) 57 want []string 58 wantTime time.Duration 59 }{ 60 { 61 name: "empty", 62 msgs: func(cp *testCriticalPath) {}, 63 }, 64 { 65 name: "duplicate", 66 msgs: func(cp *testCriticalPath) { 67 cp.start(0, 0, []string{"a"}, nil) 68 cp.start(1, 0, []string{"a"}, nil) 69 cp.finish(0, 1000) 70 cp.finish(0, 2000) 71 }, 72 want: []string{"a"}, 73 wantTime: 1000, 74 }, 75 { 76 name: "linear", 77 // a 78 // | 79 // b 80 // | 81 // c 82 msgs: func(cp *testCriticalPath) { 83 cp.start(0, 0, []string{"a"}, nil) 84 cp.finish(0, 1000) 85 cp.start(1, 1000, []string{"b"}, []string{"a"}) 86 cp.finish(1, 2000) 87 cp.start(2, 3000, []string{"c"}, []string{"b"}) 88 cp.finish(2, 4000) 89 }, 90 want: []string{"c", "b", "a"}, 91 wantTime: 3000, 92 }, 93 { 94 name: "diamond", 95 // a 96 // |\ 97 // b c 98 // |/ 99 // d 100 msgs: func(cp *testCriticalPath) { 101 cp.start(0, 0, []string{"a"}, nil) 102 cp.finish(0, 1000) 103 cp.start(1, 1000, []string{"b"}, []string{"a"}) 104 cp.start(2, 1000, []string{"c"}, []string{"a"}) 105 cp.finish(1, 2000) 106 cp.finish(2, 3000) 107 cp.start(3, 3000, []string{"d"}, []string{"b", "c"}) 108 cp.finish(3, 4000) 109 }, 110 want: []string{"d", "c", "a"}, 111 wantTime: 4000, 112 }, 113 { 114 name: "multiple", 115 // a d 116 // | | 117 // b e 118 // | 119 // c 120 msgs: func(cp *testCriticalPath) { 121 cp.start(0, 0, []string{"a"}, nil) 122 cp.start(3, 0, []string{"d"}, nil) 123 cp.finish(0, 1000) 124 cp.finish(3, 1000) 125 cp.start(1, 1000, []string{"b"}, []string{"a"}) 126 cp.start(4, 1000, []string{"e"}, []string{"d"}) 127 cp.finish(1, 2000) 128 cp.start(2, 2000, []string{"c"}, []string{"b"}) 129 cp.finish(2, 3000) 130 cp.finish(4, 4000) 131 132 }, 133 want: []string{"e", "d"}, 134 wantTime: 4000, 135 }, 136 } 137 for _, tt := range tests { 138 t.Run(tt.name, func(t *testing.T) { 139 cp := &testCriticalPath{ 140 criticalPath: NewCriticalPath(nil).(*criticalPath), 141 actions: make(map[int]*Action), 142 } 143 144 tt.msgs(cp) 145 146 criticalPath := cp.criticalPath.criticalPath() 147 148 var descs []string 149 for _, x := range criticalPath { 150 descs = append(descs, x.action.Description) 151 } 152 153 if !reflect.DeepEqual(descs, tt.want) { 154 t.Errorf("criticalPath.criticalPath() = %v, want %v", descs, tt.want) 155 } 156 157 var gotTime time.Duration 158 if len(criticalPath) > 0 { 159 gotTime = criticalPath[0].cumulativeDuration 160 } 161 if gotTime != tt.wantTime { 162 t.Errorf("cumulativeDuration[0].cumulativeDuration = %v, want %v", gotTime, tt.wantTime) 163 } 164 }) 165 } 166} 167