xref: /aosp_15_r20/cts/tests/mediapc/requirements/requirementsdata_test.go (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1*b7c941bbSAndroid Build Coastguard Worker// Copyright (C) 2024 The Android Open Source Project
2*b7c941bbSAndroid Build Coastguard Worker//
3*b7c941bbSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*b7c941bbSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*b7c941bbSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*b7c941bbSAndroid Build Coastguard Worker//
7*b7c941bbSAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*b7c941bbSAndroid Build Coastguard Worker//
9*b7c941bbSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*b7c941bbSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*b7c941bbSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*b7c941bbSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*b7c941bbSAndroid Build Coastguard Worker// limitations under the License.
14*b7c941bbSAndroid Build Coastguard Worker
15*b7c941bbSAndroid Build Coastguard Workerpackage requirementsdata_test
16*b7c941bbSAndroid Build Coastguard Worker
17*b7c941bbSAndroid Build Coastguard Workerimport (
18*b7c941bbSAndroid Build Coastguard Worker	"slices"
19*b7c941bbSAndroid Build Coastguard Worker	"testing"
20*b7c941bbSAndroid Build Coastguard Worker
21*b7c941bbSAndroid Build Coastguard Worker	"google.golang.org/protobuf/proto"
22*b7c941bbSAndroid Build Coastguard Worker
23*b7c941bbSAndroid Build Coastguard Worker	"google3/third_party/android/mediapc_requirements/requirements"
24*b7c941bbSAndroid Build Coastguard Worker	pb "cts/test/mediapc/requirements/requirements_go_proto"
25*b7c941bbSAndroid Build Coastguard Worker	"github.com/google/go-cmp/cmp"
26*b7c941bbSAndroid Build Coastguard Worker	"github.com/google/go-cmp/cmp/cmpopts"
27*b7c941bbSAndroid Build Coastguard Worker
28*b7c941bbSAndroid Build Coastguard Worker	_ "embed"
29*b7c941bbSAndroid Build Coastguard Worker)
30*b7c941bbSAndroid Build Coastguard Worker
31*b7c941bbSAndroid Build Coastguard Worker// MPC Requirements data from requirements.txtpb
32*b7c941bbSAndroid Build Coastguard Worker//
33*b7c941bbSAndroid Build Coastguard Worker//go:embed requirements.binbp
34*b7c941bbSAndroid Build Coastguard Workervar reqBinary []byte
35*b7c941bbSAndroid Build Coastguard Worker
36*b7c941bbSAndroid Build Coastguard Workerfunc TestUniqueRequirementIDs(t *testing.T) {
37*b7c941bbSAndroid Build Coastguard Worker	reqList := mustUnmarshalRequirementList(t)
38*b7c941bbSAndroid Build Coastguard Worker
39*b7c941bbSAndroid Build Coastguard Worker	// Requirement ids must be unique
40*b7c941bbSAndroid Build Coastguard Worker	ids := make(map[string]bool)
41*b7c941bbSAndroid Build Coastguard Worker	for _, req := range reqList.GetRequirements() {
42*b7c941bbSAndroid Build Coastguard Worker		id := req.GetId()
43*b7c941bbSAndroid Build Coastguard Worker		if ids[id] {
44*b7c941bbSAndroid Build Coastguard Worker			t.Errorf("requirement [%s] is a duplicate", id)
45*b7c941bbSAndroid Build Coastguard Worker		}
46*b7c941bbSAndroid Build Coastguard Worker		ids[id] = true
47*b7c941bbSAndroid Build Coastguard Worker	}
48*b7c941bbSAndroid Build Coastguard Worker}
49*b7c941bbSAndroid Build Coastguard Worker
50*b7c941bbSAndroid Build Coastguard Workerfunc TestUniqueRequirementNames(t *testing.T) {
51*b7c941bbSAndroid Build Coastguard Worker	reqList := mustUnmarshalRequirementList(t)
52*b7c941bbSAndroid Build Coastguard Worker
53*b7c941bbSAndroid Build Coastguard Worker	// Requirement names must be unique
54*b7c941bbSAndroid Build Coastguard Worker	nameToID := make(map[string]string) // name to id
55*b7c941bbSAndroid Build Coastguard Worker	for _, req := range reqList.GetRequirements() {
56*b7c941bbSAndroid Build Coastguard Worker		if req.HasName() {
57*b7c941bbSAndroid Build Coastguard Worker			name := req.GetName()
58*b7c941bbSAndroid Build Coastguard Worker			if nameToID[name] != "" {
59*b7c941bbSAndroid Build Coastguard Worker				t.Errorf("the name %q of requirement [%s] is a duplicate of requirement [%s]'s name", req.GetId(), name, nameToID[name])
60*b7c941bbSAndroid Build Coastguard Worker			}
61*b7c941bbSAndroid Build Coastguard Worker			nameToID[name] = req.GetId()
62*b7c941bbSAndroid Build Coastguard Worker		}
63*b7c941bbSAndroid Build Coastguard Worker	}
64*b7c941bbSAndroid Build Coastguard Worker
65*b7c941bbSAndroid Build Coastguard Worker}
66*b7c941bbSAndroid Build Coastguard Worker
67*b7c941bbSAndroid Build Coastguard Workerfunc TestAllTestConfigsSpecifiedAndUsed(t *testing.T) {
68*b7c941bbSAndroid Build Coastguard Worker	reqList := mustUnmarshalRequirementList(t)
69*b7c941bbSAndroid Build Coastguard Worker
70*b7c941bbSAndroid Build Coastguard Worker	for _, req := range reqList.GetRequirements() {
71*b7c941bbSAndroid Build Coastguard Worker		if !req.HasName() {
72*b7c941bbSAndroid Build Coastguard Worker			continue // Do not check requirements that are not implemented yet
73*b7c941bbSAndroid Build Coastguard Worker		}
74*b7c941bbSAndroid Build Coastguard Worker
75*b7c941bbSAndroid Build Coastguard Worker		t.Run(req.GetName(), func(t *testing.T) {
76*b7c941bbSAndroid Build Coastguard Worker
77*b7c941bbSAndroid Build Coastguard Worker			specifiedTestConfigs := []string{}
78*b7c941bbSAndroid Build Coastguard Worker			for id := range req.GetTestConfigs() {
79*b7c941bbSAndroid Build Coastguard Worker				specifiedTestConfigs = append(specifiedTestConfigs, id)
80*b7c941bbSAndroid Build Coastguard Worker			}
81*b7c941bbSAndroid Build Coastguard Worker
82*b7c941bbSAndroid Build Coastguard Worker			usedTestConfigs := []string{}
83*b7c941bbSAndroid Build Coastguard Worker			for _, spec := range req.GetSpecs() {
84*b7c941bbSAndroid Build Coastguard Worker				if !slices.Contains(usedTestConfigs, spec.GetTestConfigId()) {
85*b7c941bbSAndroid Build Coastguard Worker					usedTestConfigs = append(usedTestConfigs, spec.GetTestConfigId())
86*b7c941bbSAndroid Build Coastguard Worker				}
87*b7c941bbSAndroid Build Coastguard Worker			}
88*b7c941bbSAndroid Build Coastguard Worker
89*b7c941bbSAndroid Build Coastguard Worker			if diff := cmp.Diff(specifiedTestConfigs, usedTestConfigs, cmpopts.SortSlices(
90*b7c941bbSAndroid Build Coastguard Worker				func(a, b string) bool { return a < b })); diff != "" {
91*b7c941bbSAndroid Build Coastguard Worker				t.Errorf("Specified test configs do not match used test configs (-want +got):\n%s", diff)
92*b7c941bbSAndroid Build Coastguard Worker			}
93*b7c941bbSAndroid Build Coastguard Worker		})
94*b7c941bbSAndroid Build Coastguard Worker	}
95*b7c941bbSAndroid Build Coastguard Worker}
96*b7c941bbSAndroid Build Coastguard Worker
97*b7c941bbSAndroid Build Coastguard Workerfunc TestConfigMeasurementsValid(t *testing.T) {
98*b7c941bbSAndroid Build Coastguard Worker	reqList := mustUnmarshalRequirementList(t)
99*b7c941bbSAndroid Build Coastguard Worker
100*b7c941bbSAndroid Build Coastguard Worker	for _, req := range reqList.GetRequirements() {
101*b7c941bbSAndroid Build Coastguard Worker		if !req.HasName() {
102*b7c941bbSAndroid Build Coastguard Worker			continue // Do not check requirements that are not implemented yet
103*b7c941bbSAndroid Build Coastguard Worker		}
104*b7c941bbSAndroid Build Coastguard Worker
105*b7c941bbSAndroid Build Coastguard Worker		t.Run(req.GetName(), func(t *testing.T) {
106*b7c941bbSAndroid Build Coastguard Worker			for measurementName, measurement := range req.GetMeasurements() {
107*b7c941bbSAndroid Build Coastguard Worker				if measurement.GetComparison() != pb.Comparison_COMPARISON_CONFIG {
108*b7c941bbSAndroid Build Coastguard Worker					continue // Do not check measurements that are not config measurements
109*b7c941bbSAndroid Build Coastguard Worker				}
110*b7c941bbSAndroid Build Coastguard Worker
111*b7c941bbSAndroid Build Coastguard Worker				t.Run(measurementName, func(t *testing.T) {
112*b7c941bbSAndroid Build Coastguard Worker					measurementValues := make(map[string]*pb.RequiredValue)
113*b7c941bbSAndroid Build Coastguard Worker					for _, spec := range req.GetSpecs() {
114*b7c941bbSAndroid Build Coastguard Worker						val, ok := measurementValues[spec.GetTestConfigId()]
115*b7c941bbSAndroid Build Coastguard Worker						if !ok {
116*b7c941bbSAndroid Build Coastguard Worker							measurementValues[spec.GetTestConfigId()] = spec.GetRequiredValues()[measurementName]
117*b7c941bbSAndroid Build Coastguard Worker						} else if !proto.Equal(val, spec.GetRequiredValues()[measurementName]) {
118*b7c941bbSAndroid Build Coastguard Worker							t.Errorf("Test config [%s] has multiple different values for measurement [%s]: [%v] and [%v]", spec.GetTestConfigId(), measurementName, spec.GetRequiredValues()[measurementName], val)
119*b7c941bbSAndroid Build Coastguard Worker						}
120*b7c941bbSAndroid Build Coastguard Worker					}
121*b7c941bbSAndroid Build Coastguard Worker				})
122*b7c941bbSAndroid Build Coastguard Worker			}
123*b7c941bbSAndroid Build Coastguard Worker
124*b7c941bbSAndroid Build Coastguard Worker		})
125*b7c941bbSAndroid Build Coastguard Worker	}
126*b7c941bbSAndroid Build Coastguard Worker}
127*b7c941bbSAndroid Build Coastguard Worker
128*b7c941bbSAndroid Build Coastguard Workerfunc TestConfigVariantsValid(t *testing.T) {
129*b7c941bbSAndroid Build Coastguard Worker	reqList := mustUnmarshalRequirementList(t)
130*b7c941bbSAndroid Build Coastguard Worker
131*b7c941bbSAndroid Build Coastguard Worker	for _, req := range reqList.GetRequirements() {
132*b7c941bbSAndroid Build Coastguard Worker		if !req.HasName() {
133*b7c941bbSAndroid Build Coastguard Worker			continue // Do not check requirements that are not implemented yet
134*b7c941bbSAndroid Build Coastguard Worker		}
135*b7c941bbSAndroid Build Coastguard Worker
136*b7c941bbSAndroid Build Coastguard Worker		t.Run(req.GetName(), func(t *testing.T) {
137*b7c941bbSAndroid Build Coastguard Worker			for configID := range req.GetTestConfigs() {
138*b7c941bbSAndroid Build Coastguard Worker
139*b7c941bbSAndroid Build Coastguard Worker				// Check that all test configs have the same variants
140*b7c941bbSAndroid Build Coastguard Worker				t.Run(configID, func(t *testing.T) {
141*b7c941bbSAndroid Build Coastguard Worker					specToVariants := make(map[int64][]string)
142*b7c941bbSAndroid Build Coastguard Worker					for mpc, spec := range req.GetSpecs() {
143*b7c941bbSAndroid Build Coastguard Worker						if spec.GetTestConfigId() == configID {
144*b7c941bbSAndroid Build Coastguard Worker							specToVariants[mpc] = []string{}
145*b7c941bbSAndroid Build Coastguard Worker							for variantID := range spec.GetVariantSpecs() {
146*b7c941bbSAndroid Build Coastguard Worker								specToVariants[mpc] = append(specToVariants[mpc], variantID)
147*b7c941bbSAndroid Build Coastguard Worker							}
148*b7c941bbSAndroid Build Coastguard Worker						}
149*b7c941bbSAndroid Build Coastguard Worker					}
150*b7c941bbSAndroid Build Coastguard Worker
151*b7c941bbSAndroid Build Coastguard Worker					prev := []string{}
152*b7c941bbSAndroid Build Coastguard Worker					for _, variants := range specToVariants {
153*b7c941bbSAndroid Build Coastguard Worker						if len(prev) > 0 {
154*b7c941bbSAndroid Build Coastguard Worker							if diff := cmp.Diff(prev, variants, cmpopts.SortSlices(
155*b7c941bbSAndroid Build Coastguard Worker								func(a, b string) bool { return a < b })); diff != "" {
156*b7c941bbSAndroid Build Coastguard Worker								t.Errorf("Test config [%s] missing variants (-want +got):\n%s", configID, diff)
157*b7c941bbSAndroid Build Coastguard Worker							}
158*b7c941bbSAndroid Build Coastguard Worker						}
159*b7c941bbSAndroid Build Coastguard Worker						prev = variants
160*b7c941bbSAndroid Build Coastguard Worker					}
161*b7c941bbSAndroid Build Coastguard Worker				})
162*b7c941bbSAndroid Build Coastguard Worker			}
163*b7c941bbSAndroid Build Coastguard Worker		})
164*b7c941bbSAndroid Build Coastguard Worker	}
165*b7c941bbSAndroid Build Coastguard Worker}
166*b7c941bbSAndroid Build Coastguard Worker
167*b7c941bbSAndroid Build Coastguard Workerfunc TestProtoFieldNumbersAreUniqueAndValid(t *testing.T) {
168*b7c941bbSAndroid Build Coastguard Worker	reqList := mustUnmarshalRequirementList(t)
169*b7c941bbSAndroid Build Coastguard Worker
170*b7c941bbSAndroid Build Coastguard Worker	usedReqNumbers := make(map[int32]bool)
171*b7c941bbSAndroid Build Coastguard Worker	for _, req := range reqList.GetRequirements() {
172*b7c941bbSAndroid Build Coastguard Worker		for testConfigID, testConfig := range req.GetTestConfigs() {
173*b7c941bbSAndroid Build Coastguard Worker			if !testConfig.HasProtoFieldNumber() {
174*b7c941bbSAndroid Build Coastguard Worker				continue
175*b7c941bbSAndroid Build Coastguard Worker			}
176*b7c941bbSAndroid Build Coastguard Worker
177*b7c941bbSAndroid Build Coastguard Worker			if usedReqNumbers[testConfig.GetProtoFieldNumber()] {
178*b7c941bbSAndroid Build Coastguard Worker				t.Errorf("Test config [%s] has the same proto field number [%d] as another test config", testConfigID, testConfig.GetProtoFieldNumber())
179*b7c941bbSAndroid Build Coastguard Worker			} else if testConfig.GetProtoFieldNumber() <= 0 {
180*b7c941bbSAndroid Build Coastguard Worker				t.Errorf("Test config [%s] has an invalid proto field number [%d]", testConfigID, testConfig.GetProtoFieldNumber())
181*b7c941bbSAndroid Build Coastguard Worker			} else {
182*b7c941bbSAndroid Build Coastguard Worker				usedReqNumbers[testConfig.GetProtoFieldNumber()] = true
183*b7c941bbSAndroid Build Coastguard Worker			}
184*b7c941bbSAndroid Build Coastguard Worker		}
185*b7c941bbSAndroid Build Coastguard Worker
186*b7c941bbSAndroid Build Coastguard Worker		t.Run(req.GetId(), func(t *testing.T) {
187*b7c941bbSAndroid Build Coastguard Worker			usedMeasurementNumbers := make(map[int32]bool)
188*b7c941bbSAndroid Build Coastguard Worker
189*b7c941bbSAndroid Build Coastguard Worker			for _, measurement := range req.GetMeasurements() {
190*b7c941bbSAndroid Build Coastguard Worker				if !measurement.HasProtoFieldNumber() {
191*b7c941bbSAndroid Build Coastguard Worker					continue
192*b7c941bbSAndroid Build Coastguard Worker				}
193*b7c941bbSAndroid Build Coastguard Worker
194*b7c941bbSAndroid Build Coastguard Worker				if usedMeasurementNumbers[measurement.GetProtoFieldNumber()] {
195*b7c941bbSAndroid Build Coastguard Worker					t.Errorf("Measurement [%s] has the same proto field number [%d] as another measurement", measurement.GetId(), measurement.GetProtoFieldNumber())
196*b7c941bbSAndroid Build Coastguard Worker				} else if measurement.GetProtoFieldNumber() <= 2 {
197*b7c941bbSAndroid Build Coastguard Worker					t.Errorf("Measurement [%s] has an invalid proto field number [%d]", measurement.GetId(), measurement.GetProtoFieldNumber())
198*b7c941bbSAndroid Build Coastguard Worker				} else {
199*b7c941bbSAndroid Build Coastguard Worker					usedMeasurementNumbers[measurement.GetProtoFieldNumber()] = true
200*b7c941bbSAndroid Build Coastguard Worker				}
201*b7c941bbSAndroid Build Coastguard Worker			}
202*b7c941bbSAndroid Build Coastguard Worker		})
203*b7c941bbSAndroid Build Coastguard Worker	}
204*b7c941bbSAndroid Build Coastguard Worker}
205*b7c941bbSAndroid Build Coastguard Worker
206*b7c941bbSAndroid Build Coastguard Workerfunc mustUnmarshalRequirementList(t *testing.T) *pb.RequirementList {
207*b7c941bbSAndroid Build Coastguard Worker	t.Helper()
208*b7c941bbSAndroid Build Coastguard Worker	reqList, err := requirements.UnmarshalRequirementList(reqBinary)
209*b7c941bbSAndroid Build Coastguard Worker	if err != nil {
210*b7c941bbSAndroid Build Coastguard Worker		t.Fatalf("failed to unmarshal reqBinary: %v", err)
211*b7c941bbSAndroid Build Coastguard Worker	}
212*b7c941bbSAndroid Build Coastguard Worker	return reqList
213*b7c941bbSAndroid Build Coastguard Worker}
214