1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 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 */ 15 16package rec 17 18import ( 19 "context" 20 "crypto/md5" 21 "fmt" 22 "fotff/res" 23 "fotff/tester" 24 "github.com/sirupsen/logrus" 25 "math/rand" 26 "os" 27 "strconv" 28 "strings" 29 "sync" 30 "testing" 31 "time" 32) 33 34type FotffMocker struct { 35 FirstFail int 36 steps []string 37 lock sync.Mutex 38 runningPkg map[string]string 39} 40 41func init() { 42 rand.Seed(time.Now().UnixNano()) 43} 44 45func TestMain(m *testing.M) { 46 defer os.RemoveAll(".fotff") 47 defer os.RemoveAll("logs") 48 m.Run() 49} 50 51func NewFotffMocker(stepsNum int, firstFail int) *FotffMocker { 52 randomPrefix := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d", rand.Int()))))[:4] 53 steps := make([]string, stepsNum) 54 for i := 1; i <= stepsNum; i++ { 55 steps[i-1] = fmt.Sprintf("%s_%s", randomPrefix, strconv.Itoa(i)) 56 } 57 return &FotffMocker{ 58 FirstFail: firstFail, 59 steps: steps, 60 runningPkg: map[string]string{}, 61 } 62} 63 64func (f *FotffMocker) TaskName() string { 65 return "mocker" 66} 67 68func (f *FotffMocker) Prepare(pkgDir string, device string, ctx context.Context) error { 69 return nil 70} 71 72func (f *FotffMocker) DoTestTask(device string, ctx context.Context) ([]tester.Result, error) { 73 time.Sleep(time.Duration(rand.Intn(1)) * time.Millisecond) 74 select { 75 case <-ctx.Done(): 76 return nil, context.Canceled 77 default: 78 } 79 return []tester.Result{{TestCaseName: f.TestCaseName(), Status: tester.ResultFail}}, nil 80} 81 82func (f *FotffMocker) DoTestCase(device string, testcase string, ctx context.Context) (tester.Result, error) { 83 time.Sleep(time.Duration(rand.Intn(1)) * time.Millisecond) 84 select { 85 case <-ctx.Done(): 86 return tester.Result{}, context.Canceled 87 default: 88 } 89 f.lock.Lock() 90 _, pkgPrefix, _ := strings.Cut(f.runningPkg[device], "_") 91 pkgOrder, _ := strconv.Atoi(pkgPrefix) 92 f.lock.Unlock() 93 if pkgOrder >= f.FirstFail { 94 logrus.Infof("mock: test %s at %s done, result is %s", testcase, device, tester.ResultFail) 95 return tester.Result{TestCaseName: testcase, Status: tester.ResultFail}, nil 96 } 97 logrus.Infof("mock: test %s at %s done, result is %s", testcase, device, tester.ResultPass) 98 return tester.Result{TestCaseName: testcase, Status: tester.ResultPass}, nil 99} 100 101func (f *FotffMocker) DoTestCases(device string, testcases []string, ctx context.Context) ([]tester.Result, error) { 102 var ret []tester.Result 103 for _, testcase := range testcases { 104 r, err := f.DoTestCase(device, testcase, ctx) 105 if err != nil { 106 return nil, err 107 } 108 ret = append(ret, r) 109 } 110 return ret, nil 111} 112 113func (f *FotffMocker) Flash(device string, pkg string, ctx context.Context) error { 114 time.Sleep(time.Duration(rand.Intn(1)) * time.Millisecond) 115 select { 116 case <-ctx.Done(): 117 return context.Canceled 118 default: 119 } 120 f.lock.Lock() 121 f.runningPkg[device] = pkg 122 logrus.Infof("mock: flash %s to %s done", pkg, device) 123 f.lock.Unlock() 124 return nil 125} 126 127func (f *FotffMocker) LastIssue(pkg string) (string, error) { 128 return "issue" + pkg, nil 129} 130 131func (f *FotffMocker) Steps(from, to string) (ret []string, err error) { 132 return f.steps, nil 133} 134 135func (f *FotffMocker) GetNewer(cur string) (string, error) { 136 return "", nil 137} 138 139func (f *FotffMocker) PkgDir(pkg string) string { 140 return pkg 141} 142 143func (f *FotffMocker) TestCaseName() string { 144 return "MOCK_FAILED_TEST_CASE" 145} 146 147func (f *FotffMocker) Last() string { 148 return f.steps[len(f.steps)-1] 149} 150 151func TestFindOutTheFirstFail(t *testing.T) { 152 tests := []struct { 153 name string 154 mocker *FotffMocker 155 }{ 156 { 157 name: "0-1(X)", 158 mocker: NewFotffMocker(1, 1), 159 }, 160 { 161 name: "0-1(X)-2", 162 mocker: NewFotffMocker(2, 1), 163 }, 164 { 165 name: "0-1-2(X)", 166 mocker: NewFotffMocker(2, 2), 167 }, 168 { 169 name: "0-1(X)-2-3", 170 mocker: NewFotffMocker(3, 1), 171 }, 172 { 173 name: "0-1-2(X)-3", 174 mocker: NewFotffMocker(3, 2), 175 }, 176 { 177 name: "0-1-2-3(X)", 178 mocker: NewFotffMocker(3, 3), 179 }, 180 { 181 name: "0-1(X)-2-3-4", 182 mocker: NewFotffMocker(4, 1), 183 }, 184 { 185 name: "0-1-2(X)-3-4", 186 mocker: NewFotffMocker(4, 2), 187 }, 188 { 189 name: "0-1-2-3(X)-4", 190 mocker: NewFotffMocker(4, 3), 191 }, 192 { 193 name: "0-1-2-3-4(X)", 194 mocker: NewFotffMocker(4, 4), 195 }, 196 { 197 name: "0-1(X)-2-3-4-5", 198 mocker: NewFotffMocker(5, 1), 199 }, 200 { 201 name: "0-1-2(X)-3-4-5", 202 mocker: NewFotffMocker(5, 2), 203 }, 204 { 205 name: "0-1-2-3(X)-4-5", 206 mocker: NewFotffMocker(5, 3), 207 }, 208 { 209 name: "0-1-2-3-4(X)-5", 210 mocker: NewFotffMocker(5, 4), 211 }, 212 { 213 name: "0-1-2-3-4-5(X)", 214 mocker: NewFotffMocker(5, 5), 215 }, 216 { 217 name: "0-1-2...262143(X)...1048575", 218 mocker: NewFotffMocker(1048575, 262143), 219 }, 220 { 221 name: "0-1-2...262144(X)...1048575", 222 mocker: NewFotffMocker(1048575, 262144), 223 }, 224 { 225 name: "0-1-2...262145(X)...1048575", 226 mocker: NewFotffMocker(1048575, 262145), 227 }, 228 { 229 name: "0-1-2...262143(X)...1048576", 230 mocker: NewFotffMocker(1048576, 262143), 231 }, 232 { 233 name: "0-1-2...262144(X)...1048576", 234 mocker: NewFotffMocker(1048576, 262144), 235 }, 236 { 237 name: "0-1-2...262145(X)...1048576", 238 mocker: NewFotffMocker(1048576, 262145), 239 }, 240 { 241 name: "0-1-2...262143(X)...1048577", 242 mocker: NewFotffMocker(1048577, 262143), 243 }, 244 { 245 name: "0-1-2...262144(X)...1048577", 246 mocker: NewFotffMocker(1048577, 262144), 247 }, 248 { 249 name: "0-1-2...262145(X)...1048577", 250 mocker: NewFotffMocker(1048577, 262145), 251 }, 252 { 253 name: "0-1-2...1234567(X)...10000000", 254 mocker: NewFotffMocker(10000000, 1234567), 255 }, 256 { 257 name: "0-1-2...1234567(X)...100000001", 258 mocker: NewFotffMocker(10000001, 1234567), 259 }, 260 { 261 name: "0-1-2...7654321(X)...10000000", 262 mocker: NewFotffMocker(10000000, 7654321), 263 }, 264 { 265 name: "0-1-2...7654321(X)...10000001", 266 mocker: NewFotffMocker(10000001, 7654321), 267 }, 268 { 269 name: "0-1(X)-2...10000000", 270 mocker: NewFotffMocker(10000000, 1), 271 }, 272 { 273 name: "0-1(X)-2...10000001", 274 mocker: NewFotffMocker(10000001, 1), 275 }, 276 { 277 name: "0-1-2...10000000(X)", 278 mocker: NewFotffMocker(10000000, 10000000), 279 }, 280 { 281 name: "0-1-2...10000001(X)", 282 mocker: NewFotffMocker(10000001, 10000001), 283 }, 284 } 285 for i := 1; i <= 5; i++ { 286 res.Fake(i) 287 for _, tt := range tests { 288 t.Run(fmt.Sprintf("RES%d:%s", i, tt.name), func(t *testing.T) { 289 ret, err := FindOutTheFirstFail(tt.mocker, tt.mocker, tt.mocker.TestCaseName(), "0", tt.mocker.Last()) 290 if err != nil { 291 t.Errorf("err: expcect: <nil>, actual: %v", err) 292 } 293 expectIssue, _ := tt.mocker.LastIssue(tt.mocker.steps[tt.mocker.FirstFail-1]) 294 if ret != expectIssue { 295 t.Errorf("fotff result: expect: %s, actual: %s", expectIssue, ret) 296 } 297 }) 298 } 299 } 300} 301