blob: 32dd5fd52d61f500e81dd25489e048b97f9e9152 [file] [log] [blame]
Bob Badour9ee7d032021-10-25 16:51:48 -07001// Copyright 2021 Google LLC
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 compliance
16
17import (
18 "bytes"
19 "fmt"
20 "sort"
21 "strings"
22 "testing"
23)
24
25func TestPolicy_edgeConditions(t *testing.T) {
26 tests := []struct {
27 name string
28 edge annotated
29 treatAsAggregate bool
30 otherCondition string
31 expectedDepActions []string
32 expectedTargetConditions []string
33 }{
34 {
35 name: "firstparty",
36 edge: annotated{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -080037 expectedDepActions: []string{},
Bob Badour9ee7d032021-10-25 16:51:48 -070038 expectedTargetConditions: []string{},
39 },
40 {
41 name: "notice",
42 edge: annotated{"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -080043 expectedDepActions: []string{},
Bob Badour9ee7d032021-10-25 16:51:48 -070044 expectedTargetConditions: []string{},
45 },
46 {
47 name: "fponlgpl",
48 edge: annotated{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}},
49 expectedDepActions: []string{
Bob Badour103eb0f2022-01-10 13:50:57 -080050 "apacheBin.meta_lic:lgplLib.meta_lic:restricted_allows_dynamic_linking",
51 "lgplLib.meta_lic:lgplLib.meta_lic:restricted_allows_dynamic_linking",
Bob Badour9ee7d032021-10-25 16:51:48 -070052 },
53 expectedTargetConditions: []string{},
54 },
55 {
56 name: "fponlgpldynamic",
57 edge: annotated{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}},
58 expectedDepActions: []string{},
59 expectedTargetConditions: []string{},
60 },
61 {
62 name: "fpongpl",
63 edge: annotated{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}},
64 expectedDepActions: []string{
65 "apacheBin.meta_lic:gplLib.meta_lic:restricted",
66 "gplLib.meta_lic:gplLib.meta_lic:restricted",
67 },
68 expectedTargetConditions: []string{},
69 },
70 {
71 name: "fpongpldynamic",
72 edge: annotated{"apacheBin.meta_lic", "gplLib.meta_lic", []string{"dynamic"}},
73 expectedDepActions: []string{
74 "apacheBin.meta_lic:gplLib.meta_lic:restricted",
75 "gplLib.meta_lic:gplLib.meta_lic:restricted",
76 },
77 expectedTargetConditions: []string{},
78 },
79 {
80 name: "independentmodule",
81 edge: annotated{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
82 expectedDepActions: []string{},
83 expectedTargetConditions: []string{},
84 },
85 {
86 name: "independentmodulestatic",
87 edge: annotated{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}},
88 expectedDepActions: []string{
Bob Badour103eb0f2022-01-10 13:50:57 -080089 "apacheBin.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception",
90 "gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception",
Bob Badour9ee7d032021-10-25 16:51:48 -070091 },
92 expectedTargetConditions: []string{},
93 },
94 {
95 name: "dependentmodule",
96 edge: annotated{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}},
97 expectedDepActions: []string{
Bob Badour103eb0f2022-01-10 13:50:57 -080098 "dependentModule.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception",
99 "gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception",
Bob Badour9ee7d032021-10-25 16:51:48 -0700100 },
101 expectedTargetConditions: []string{},
102 },
103
104 {
105 name: "lgplonfp",
106 edge: annotated{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -0800107 expectedDepActions: []string{},
108 expectedTargetConditions: []string{"lgplBin.meta_lic:restricted_allows_dynamic_linking"},
Bob Badour9ee7d032021-10-25 16:51:48 -0700109 },
110 {
111 name: "lgplonfpdynamic",
112 edge: annotated{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
113 expectedDepActions: []string{},
114 expectedTargetConditions: []string{},
115 },
116 {
117 name: "gplonfp",
118 edge: annotated{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -0800119 expectedDepActions: []string{},
Bob Badour9ee7d032021-10-25 16:51:48 -0700120 expectedTargetConditions: []string{"gplBin.meta_lic:restricted"},
121 },
122 {
123 name: "gplcontainer",
124 edge: annotated{"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
125 treatAsAggregate: true,
Bob Badour103eb0f2022-01-10 13:50:57 -0800126 expectedDepActions: []string{},
Bob Badour9ee7d032021-10-25 16:51:48 -0700127 expectedTargetConditions: []string{"gplContainer.meta_lic:restricted"},
128 },
129 {
130 name: "gploncontainer",
131 edge: annotated{"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}},
132 treatAsAggregate: true,
133 otherCondition: "gplLib.meta_lic:restricted",
134 expectedDepActions: []string{
135 "apacheContainer.meta_lic:gplLib.meta_lic:restricted",
Bob Badour9ee7d032021-10-25 16:51:48 -0700136 "apacheLib.meta_lic:gplLib.meta_lic:restricted",
137 "gplLib.meta_lic:gplLib.meta_lic:restricted",
138 },
139 expectedTargetConditions: []string{},
140 },
141 {
142 name: "gplonbin",
143 edge: annotated{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}},
144 treatAsAggregate: false,
145 otherCondition: "gplLib.meta_lic:restricted",
146 expectedDepActions: []string{
147 "apacheBin.meta_lic:gplLib.meta_lic:restricted",
Bob Badour9ee7d032021-10-25 16:51:48 -0700148 "apacheLib.meta_lic:gplLib.meta_lic:restricted",
149 "gplLib.meta_lic:gplLib.meta_lic:restricted",
150 },
151 expectedTargetConditions: []string{"gplLib.meta_lic:restricted"},
152 },
153 {
154 name: "gplonfpdynamic",
155 edge: annotated{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}},
156 expectedDepActions: []string{},
157 expectedTargetConditions: []string{"gplBin.meta_lic:restricted"},
158 },
159 {
160 name: "independentmodulereverse",
161 edge: annotated{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}},
162 expectedDepActions: []string{},
163 expectedTargetConditions: []string{},
164 },
165 {
166 name: "independentmodulereversestatic",
167 edge: annotated{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -0800168 expectedDepActions: []string{},
169 expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted_with_classpath_exception"},
Bob Badour9ee7d032021-10-25 16:51:48 -0700170 },
171 {
172 name: "dependentmodulereverse",
173 edge: annotated{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}},
174 expectedDepActions: []string{},
Bob Badour103eb0f2022-01-10 13:50:57 -0800175 expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted_with_classpath_exception"},
Bob Badour9ee7d032021-10-25 16:51:48 -0700176 },
177 {
178 name: "ponr",
179 edge: annotated{"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}},
180 expectedDepActions: []string{
181 "proprietary.meta_lic:gplLib.meta_lic:restricted",
182 "gplLib.meta_lic:gplLib.meta_lic:restricted",
183 },
184 expectedTargetConditions: []string{},
185 },
186 {
187 name: "ronp",
188 edge: annotated{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -0800189 expectedDepActions: []string{},
Bob Badour9ee7d032021-10-25 16:51:48 -0700190 expectedTargetConditions: []string{"gplBin.meta_lic:restricted"},
191 },
192 {
193 name: "noticeonb_e_o",
194 edge: annotated{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -0800195 expectedDepActions: []string{},
Bob Badour9ee7d032021-10-25 16:51:48 -0700196 expectedTargetConditions: []string{},
197 },
198 {
199 name: "b_e_oonnotice",
200 edge: annotated{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -0800201 expectedDepActions: []string{},
Bob Badour9ee7d032021-10-25 16:51:48 -0700202 expectedTargetConditions: []string{},
203 },
204 {
205 name: "noticeonrecip",
206 edge: annotated{"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -0800207 expectedDepActions: []string{},
Bob Badour9ee7d032021-10-25 16:51:48 -0700208 expectedTargetConditions: []string{},
209 },
210 {
211 name: "reciponnotice",
212 edge: annotated{"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}},
Bob Badour103eb0f2022-01-10 13:50:57 -0800213 expectedDepActions: []string{},
Bob Badour9ee7d032021-10-25 16:51:48 -0700214 expectedTargetConditions: []string{},
215 },
216 }
217 for _, tt := range tests {
218 t.Run(tt.name, func(t *testing.T) {
219 fs := make(testFS)
220 stderr := &bytes.Buffer{}
221 target := meta[tt.edge.target] + fmt.Sprintf("deps: {\n file: \"%s\"\n", tt.edge.dep)
222 for _, ann := range tt.edge.annotations {
223 target += fmt.Sprintf(" annotations: \"%s\"\n", ann)
224 }
225 fs[tt.edge.target] = []byte(target + "}\n")
226 fs[tt.edge.dep] = []byte(meta[tt.edge.dep])
227 lg, err := ReadLicenseGraph(&fs, stderr, []string{tt.edge.target})
228 if err != nil {
Colin Cross179ec3e2022-01-27 15:47:09 -0800229 t.Errorf("unexpected error reading graph: %s", err)
Bob Badour9ee7d032021-10-25 16:51:48 -0700230 return
231 }
Bob Badour103eb0f2022-01-10 13:50:57 -0800232 edge := lg.Edges()[0]
Bob Badour9ee7d032021-10-25 16:51:48 -0700233 // simulate a condition inherited from another edge/dependency.
234 otherTarget := ""
235 otherCondition := ""
Bob Badour103eb0f2022-01-10 13:50:57 -0800236 var otn *TargetNode
Bob Badour9ee7d032021-10-25 16:51:48 -0700237 if len(tt.otherCondition) > 0 {
238 fields := strings.Split(tt.otherCondition, ":")
239 otherTarget = fields[0]
240 otherCondition = fields[1]
Bob Badour103eb0f2022-01-10 13:50:57 -0800241 otn = &TargetNode{name: otherTarget}
Bob Badour9ee7d032021-10-25 16:51:48 -0700242 // other target must exist in graph
Bob Badour103eb0f2022-01-10 13:50:57 -0800243 lg.targets[otherTarget] = otn
244 otn.licenseConditions = LicenseConditionSet(RecognizedConditionNames[otherCondition])
245 }
246 targets := make(map[string]*TargetNode)
247 targets[edge.target.name] = edge.target
248 targets[edge.dependency.name] = edge.dependency
249 if otn != nil {
250 targets[otn.name] = otn
Bob Badour9ee7d032021-10-25 16:51:48 -0700251 }
252 if tt.expectedDepActions != nil {
Bob Badour103eb0f2022-01-10 13:50:57 -0800253 t.Run("depConditionsPropagatingToTarget", func(t *testing.T) {
254 depConditions := edge.dependency.LicenseConditions()
255 if otherTarget != "" {
256 // simulate a sub-dependency's condition having already propagated up to dep and about to go to target
257 otherCs := otn.LicenseConditions()
258 depConditions |= otherCs
Bob Badour9ee7d032021-10-25 16:51:48 -0700259 }
Bob Badour103eb0f2022-01-10 13:50:57 -0800260 t.Logf("calculate target actions for edge=%s, dep conditions=%04x, treatAsAggregate=%v", edge.String(), depConditions, tt.treatAsAggregate)
261 csActual := depConditionsPropagatingToTarget(lg, edge, depConditions, tt.treatAsAggregate)
262 t.Logf("calculated target conditions as %04x{%s}", csActual, strings.Join(csActual.Names(), ", "))
263 csExpected := NewLicenseConditionSet()
264 for _, triple := range tt.expectedDepActions {
265 fields := strings.Split(triple, ":")
266 expectedConditions := NewLicenseConditionSet()
267 for _, cname := range fields[2:] {
268 expectedConditions = expectedConditions.Plus(RecognizedConditionNames[cname])
269 }
270 csExpected |= expectedConditions
271 }
272 t.Logf("expected target conditions as %04x{%s}", csExpected, strings.Join(csExpected.Names(), ", "))
273 if csActual != csExpected {
274 t.Errorf("unexpected license conditions: got %04x, want %04x", csActual, csExpected)
275 }
276 })
Bob Badour9ee7d032021-10-25 16:51:48 -0700277 }
278 if tt.expectedTargetConditions != nil {
Bob Badour103eb0f2022-01-10 13:50:57 -0800279 t.Run("targetConditionsPropagatingToDep", func(t *testing.T) {
280 targetConditions := edge.target.LicenseConditions()
281 if otherTarget != "" {
282 targetConditions = targetConditions.Union(otn.licenseConditions)
283 }
284 t.Logf("calculate dep conditions for edge=%s, target conditions=%v, treatAsAggregate=%v", edge.String(), targetConditions.Names(), tt.treatAsAggregate)
285 cs := targetConditionsPropagatingToDep(lg, edge, targetConditions, tt.treatAsAggregate)
286 t.Logf("calculated dep conditions as %v", cs.Names())
287 actual := cs.Names()
288 sort.Strings(actual)
289 expected := make([]string, 0)
290 for _, expectedDepCondition := range tt.expectedTargetConditions {
291 expected = append(expected, strings.Split(expectedDepCondition, ":")[1])
292 }
293 sort.Strings(expected)
294 if len(actual) != len(expected) {
295 t.Errorf("unexpected number of target conditions: got %v with %d conditions, want %v with %d conditions",
296 actual, len(actual), expected, len(expected))
297 } else {
298 for i := 0; i < len(actual); i++ {
299 if actual[i] != expected[i] {
300 t.Errorf("unexpected target condition at element %d: got %q, want %q",
301 i, actual[i], expected[i])
302 }
Bob Badour9ee7d032021-10-25 16:51:48 -0700303 }
304 }
Bob Badour103eb0f2022-01-10 13:50:57 -0800305 })
Bob Badour9ee7d032021-10-25 16:51:48 -0700306 }
307 })
308 }
309}