github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/cmd/mitigate_test.go (about) 1 // Copyright 2021 The gVisor Authors. 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 15 // +build amd64 16 17 package cmd 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 "os" 23 "strings" 24 "testing" 25 26 "github.com/SagerNet/gvisor/runsc/mitigate/mock" 27 ) 28 29 type executeTestCase struct { 30 name string 31 mitigateData string 32 mitigateError error 33 mitigateCPU int 34 reverseData string 35 reverseError error 36 reverseCPU int 37 } 38 39 func TestExecute(t *testing.T) { 40 41 partial := `processor : 1 42 vendor_id : AuthenticAMD 43 cpu family : 23 44 model : 49 45 model name : AMD EPYC 7B12 46 physical id : 0 47 bugs : sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass 48 power management: 49 ` 50 51 for _, tc := range []executeTestCase{ 52 { 53 name: "CascadeLake4", 54 mitigateData: mock.CascadeLake4.MakeCPUString(), 55 mitigateCPU: 2, 56 reverseData: mock.CascadeLake4.MakeSysPossibleString(), 57 reverseCPU: 4, 58 }, 59 { 60 name: "Empty", 61 mitigateData: "", 62 mitigateError: fmt.Errorf(`mitigate operation failed: no cpus found for: ""`), 63 reverseData: "", 64 reverseError: fmt.Errorf(`reverse operation failed: mismatch regex from possible: ""`), 65 }, 66 { 67 name: "Partial", 68 mitigateData: `processor : 0 69 vendor_id : AuthenticAMD 70 cpu family : 23 71 model : 49 72 model name : AMD EPYC 7B12 73 physical id : 0 74 core id : 0 75 cpu cores : 1 76 bugs : sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass 77 power management::84 78 79 ` + partial, 80 mitigateError: fmt.Errorf(`mitigate operation failed: failed to match key "core id": %q`, partial), 81 reverseData: "1-", 82 reverseError: fmt.Errorf(`reverse operation failed: mismatch regex from possible: %q`, "1-"), 83 }, 84 } { 85 t.Run(tc.name, func(t *testing.T) { 86 m := &Mitigate{ 87 dryRun: true, 88 } 89 m.doExecuteTest(t, "Mitigate", tc.mitigateData, tc.mitigateCPU, tc.mitigateError) 90 91 m.reverse = true 92 m.doExecuteTest(t, "Reverse", tc.reverseData, tc.reverseCPU, tc.reverseError) 93 }) 94 } 95 } 96 97 func TestExecuteSmoke(t *testing.T) { 98 smokeMitigate, err := ioutil.ReadFile(cpuInfo) 99 if err != nil { 100 t.Fatalf("Failed to read %s: %v", cpuInfo, err) 101 } 102 103 m := &Mitigate{ 104 dryRun: true, 105 } 106 107 m.doExecuteTest(t, "Mitigate", string(smokeMitigate), 0, nil) 108 109 smokeReverse, err := ioutil.ReadFile(allPossibleCPUs) 110 if err != nil { 111 t.Fatalf("Failed to read %s: %v", allPossibleCPUs, err) 112 } 113 114 m.reverse = true 115 m.doExecuteTest(t, "Reverse", string(smokeReverse), 0, nil) 116 } 117 118 // doExecuteTest runs Execute with the mitigate operation and reverse operation. 119 func (m *Mitigate) doExecuteTest(t *testing.T, name, data string, want int, wantErr error) { 120 t.Run(name, func(t *testing.T) { 121 file, err := ioutil.TempFile("", "outfile.txt") 122 if err != nil { 123 t.Fatalf("Failed to create tmpfile: %v", err) 124 } 125 defer os.Remove(file.Name()) 126 127 if _, err := file.WriteString(data); err != nil { 128 t.Fatalf("Failed to write to file: %v", err) 129 } 130 131 // Set fields for mitigate and dryrun to keep test hermetic. 132 m.path = file.Name() 133 134 set, err := m.doExecute() 135 if err = checkErr(wantErr, err); err != nil { 136 t.Fatalf("Mitigate error mismatch: %v", err) 137 } 138 139 // case where test should end in error or we don't care 140 // about how many cpus are returned. 141 if wantErr != nil || want < 1 { 142 return 143 } 144 got := len(set.GetRemainingList()) 145 if want != got { 146 t.Fatalf("Failed wrong number of remaining CPUs: want %d, got %d", want, got) 147 } 148 149 }) 150 } 151 152 // checkErr checks error for equality. 153 func checkErr(want, got error) error { 154 switch { 155 case want == nil && got == nil: 156 case want != nil && got == nil: 157 fallthrough 158 case want == nil && got != nil: 159 fallthrough 160 case want.Error() != strings.Trim(got.Error(), " "): 161 return fmt.Errorf("got: %v want: %v", got, want) 162 } 163 return nil 164 }