| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package main |
| |
| import ( |
| "context" |
| "encoding/json" |
| "io/ioutil" |
| "os" |
| "path/filepath" |
| "strings" |
| "testing" |
| |
| "github.com/google/go-cmp/cmp" |
| buildbucketpb "go.chromium.org/luci/buildbucket/proto" |
| "google.golang.org/protobuf/types/known/structpb" |
| ) |
| |
| func TestResolveBuildProperties(t *testing.T) { |
| t.Parallel() |
| |
| tests := []struct { |
| name string |
| inputProperties map[string]interface{} |
| versionedProperties map[string]interface{} |
| expectProperties map[string]interface{} |
| expectErr bool |
| }{ |
| { |
| name: "passes through versioned properties", |
| inputProperties: map[string]interface{}{}, |
| versionedProperties: map[string]interface{}{ |
| "foo": "bar", |
| }, |
| expectProperties: map[string]interface{}{ |
| "foo": "bar", |
| }, |
| }, |
| { |
| name: "request properties override versioned properties", |
| inputProperties: map[string]interface{}{ |
| "foo": "request_value", |
| }, |
| versionedProperties: map[string]interface{}{ |
| "foo": "versioned_value", |
| "bar": "baz", |
| }, |
| expectProperties: map[string]interface{}{ |
| "foo": "request_value", |
| "bar": "baz", |
| }, |
| }, |
| } |
| |
| for _, test := range tests { |
| t.Run(test.name, func(t *testing.T) { |
| ctx := context.Background() |
| builder := &buildbucketpb.BuilderID{ |
| Project: "fuchsia", Bucket: "ci", Builder: "bldr", |
| } |
| build := &buildbucketpb.Build{ |
| Builder: builder, |
| Input: &buildbucketpb.Build_Input{}, |
| } |
| var err error |
| build.Input.Properties, err = structpb.NewStruct(test.inputProperties) |
| if err != nil { |
| t.Fatal(err) |
| } |
| integrationDir := t.TempDir() |
| propertiesPath := filepath.Join( |
| generatedDirForBuilder(integrationDir, builder), "properties", |
| builder.Bucket, builder.Builder+".json") |
| jsonProps, err := json.Marshal(test.versionedProperties) |
| if err != nil { |
| t.Fatal(err) |
| } |
| writeFile(t, propertiesPath, []byte(jsonProps)) |
| |
| if err := resolveBuildProperties(ctx, integrationDir, build); err != nil { |
| if !test.expectErr { |
| t.Fatalf("got unexpected error: %s", err) |
| } |
| return |
| } else if test.expectErr { |
| t.Fatalf("expected error, got nil") |
| } |
| if diff := cmp.Diff(test.expectProperties, build.Input.Properties.AsMap()); diff != "" { |
| t.Errorf("resolveBuildProperties(): output differs (-want, +got):\n%s", diff) |
| } |
| }) |
| } |
| } |
| |
| func TestReadVersionedProperties(t *testing.T) { |
| t.Parallel() |
| |
| builder := &buildbucketpb.BuilderID{ |
| Project: "fuchsia", Bucket: "ci", Builder: "bldr", |
| } |
| |
| tests := []struct { |
| name string |
| // Mock files in integration.git (mapping from path to contents), with |
| // paths relative to the `generated` subdir corresponding to the |
| // builder's project. |
| files map[string]string |
| expectProperties map[string]interface{} |
| expectErr bool |
| }{ |
| { |
| name: "properties json file", |
| files: map[string]string{ |
| "properties/ci/bldr.json": `{"foo": "bar"}`, |
| }, |
| expectProperties: map[string]interface{}{ |
| "foo": "bar", |
| }, |
| }, |
| { |
| name: "bucket proto file", |
| files: map[string]string{ |
| "builders/ci/bldr.textproto": ` |
| swarming { |
| builders { |
| properties: |
| '{' |
| ' "nested_map": {' |
| ' "server": "url"' |
| ' },' |
| ' "number": 1234,' |
| ' "bool": true' |
| '}' |
| } |
| }`, |
| }, |
| expectProperties: map[string]interface{}{ |
| "nested_map": map[string]interface{}{ |
| "server": "url", |
| }, |
| "number": float64(1234), |
| "bool": true, |
| }, |
| }, |
| { |
| name: "bucket proto file with old-style path", |
| files: map[string]string{ |
| "for_review_only/buildbucket/ci/bldr.textproto": ` |
| swarming { |
| builders { |
| properties: |
| '{' |
| ' "nested_map": {' |
| ' "server": "url"' |
| ' },' |
| ' "number": 1234,' |
| ' "bool": true' |
| '}' |
| } |
| }`, |
| }, |
| expectProperties: map[string]interface{}{ |
| "nested_map": map[string]interface{}{ |
| "server": "url", |
| }, |
| "number": float64(1234), |
| "bool": true, |
| }, |
| }, |
| { |
| name: "bucket proto file with multiple builders", |
| files: map[string]string{ |
| "builders/ci/bldr.textproto": ` |
| swarming { |
| builders { |
| properties: '{"mock_property": ""}' |
| } |
| builders { |
| properties: '{"mock_property": ""}' |
| } |
| }`, |
| }, |
| expectErr: true, |
| }, |
| { |
| name: "empty bucket proto file", |
| files: map[string]string{ |
| "builders/ci/bldr.textproto": ``, |
| }, |
| expectErr: true, |
| }, |
| { |
| name: "no property file present", |
| files: map[string]string{}, |
| expectErr: true, |
| }, |
| { |
| name: "prefers JSON files to other property file formats", |
| files: map[string]string{ |
| "properties/ci/bldr.json": `{"foo": "json_property"}`, |
| "builders/ci/bldr.textproto": ` |
| swarming { |
| builders { |
| properties: '{"foo": "builders_proto_property"}' |
| } |
| }`, |
| "for_review_only/buildbucket/ci/bldr.textproto": ` |
| swarming { |
| builders { |
| properties: '{"foo": "for_review_only_proto_property"}' |
| } |
| }`, |
| }, |
| expectProperties: map[string]interface{}{ |
| "foo": "json_property", |
| }, |
| }, |
| } |
| for _, test := range tests { |
| t.Run(test.name, func(t *testing.T) { |
| ctx := context.Background() |
| integrationDir := t.TempDir() |
| projectDir := generatedDirForBuilder(integrationDir, builder) |
| for relPath, contents := range test.files { |
| absPath := filepath.Join( |
| append([]string{projectDir}, strings.Split(relPath, "/")...)...) |
| writeFile(t, absPath, []byte(contents)) |
| } |
| properties, err := readVersionedProperties(ctx, integrationDir, builder) |
| if err != nil { |
| if !test.expectErr { |
| t.Fatal(err) |
| } |
| return |
| } else if test.expectErr { |
| t.Fatalf("expected error, got nil") |
| } |
| |
| if diff := cmp.Diff(test.expectProperties, properties.AsMap()); diff != "" { |
| t.Errorf("readVersionedProperties(): output differs (-want, +got):\n%s", diff) |
| } |
| }) |
| } |
| } |
| |
| func writeFile(t *testing.T, path string, contents []byte) { |
| t.Helper() |
| if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil { |
| t.Fatal(err) |
| } |
| if err := ioutil.WriteFile(path, contents, 0o600); err != nil { |
| t.Fatal(err) |
| } |
| } |