github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/subsystem/extractor_test.go (about) 1 // Copyright 2023 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package subsystem 5 6 import ( 7 "reflect" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 ) 12 13 func TestExtractor(t *testing.T) { 14 // Objects used in tests. 15 fsPath, mmFsPath := "fs/", "mm/fs.c" 16 extProg, nfsProg, extNfsProg := []byte("ext"), []byte("nfs"), []byte("ext nfs") 17 all := &Subsystem{Name: "fs"} 18 fs := &Subsystem{Name: "fs", Parents: []*Subsystem{all}} 19 ext := &Subsystem{Name: "ext", Parents: []*Subsystem{fs}} 20 nfs := &Subsystem{Name: "nfs", Parents: []*Subsystem{fs}} 21 mm := &Subsystem{Name: "mm", Parents: []*Subsystem{all}} 22 // Tests themselves. 23 tests := []struct { 24 name string 25 crashes []*Crash 26 want []*Subsystem 27 }{ 28 { 29 name: `Make sure it works fine with just a single path`, 30 crashes: []*Crash{ 31 { 32 GuiltyPath: fsPath, 33 }, 34 }, 35 want: []*Subsystem{fs}, 36 }, 37 { 38 name: `Make sure a child shadows its parent`, 39 crashes: []*Crash{ 40 { 41 GuiltyPath: fsPath, 42 }, 43 { 44 GuiltyPath: fsPath, 45 SyzRepro: extProg, 46 }, 47 }, 48 want: []*Subsystem{ext}, 49 }, 50 { 51 name: `Reproducers hint at different subsystems`, 52 crashes: []*Crash{ 53 { 54 GuiltyPath: fsPath, 55 }, 56 { 57 GuiltyPath: fsPath, 58 SyzRepro: extProg, 59 }, 60 { 61 GuiltyPath: fsPath, 62 SyzRepro: nfsProg, 63 }, 64 }, 65 want: []*Subsystem{fs}, 66 }, 67 { 68 name: `One subsystem from reproducers is irrelevant`, 69 crashes: []*Crash{ 70 { 71 GuiltyPath: fsPath, 72 }, 73 { 74 GuiltyPath: fsPath, 75 SyzRepro: extProg, 76 }, 77 { 78 GuiltyPath: fsPath, 79 SyzRepro: extNfsProg, 80 }, 81 }, 82 want: []*Subsystem{ext}, 83 }, 84 { 85 name: `Reproducer supporting one of guilty paths`, 86 crashes: []*Crash{ 87 // The guilty paths correspond both to mm and fs. 88 { 89 GuiltyPath: mmFsPath, 90 }, 91 { 92 GuiltyPath: mmFsPath, 93 }, 94 { 95 GuiltyPath: mmFsPath, 96 }, 97 { 98 // But one reproducer points clearly to fs. 99 GuiltyPath: mmFsPath, 100 SyzRepro: extProg, 101 }, 102 }, 103 want: []*Subsystem{ext}, 104 }, 105 } 106 extractor := &Extractor{ 107 raw: &testRawExtractor{ 108 perPath: map[string][]*Subsystem{ 109 fsPath: {fs}, 110 mmFsPath: {mm, fs}, 111 }, 112 perProg: []progSubsystems{ 113 {extProg, []*Subsystem{ext}}, 114 {nfsProg, []*Subsystem{nfs}}, 115 {extNfsProg, []*Subsystem{ext, nfs}}, 116 }, 117 }, 118 } 119 for _, test := range tests { 120 ret := extractor.Extract(test.crashes) 121 assert.ElementsMatch(t, ret, test.want, test.name) 122 } 123 } 124 125 type testRawExtractor struct { 126 perPath map[string][]*Subsystem 127 perProg []progSubsystems 128 } 129 130 type progSubsystems struct { 131 prog []byte 132 ret []*Subsystem 133 } 134 135 func (e *testRawExtractor) FromPath(path string) []*Subsystem { 136 return e.perPath[path] 137 } 138 139 func (e *testRawExtractor) FromProg(progBytes []byte) []*Subsystem { 140 for _, obj := range e.perProg { 141 if reflect.DeepEqual(progBytes, obj.prog) { 142 return obj.ret 143 } 144 } 145 return nil 146 }