go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cipd/common/iid_test.go (about)

     1  // Copyright 2018 The LUCI 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  package common
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"testing"
    21  
    22  	api "go.chromium.org/luci/cipd/api/cipd/v1"
    23  
    24  	. "github.com/smartystreets/goconvey/convey"
    25  	. "go.chromium.org/luci/common/testing/assertions"
    26  )
    27  
    28  func TestValidateInstanceID(t *testing.T) {
    29  	t.Parallel()
    30  
    31  	good := []string{
    32  		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    33  		"0123456789abcdefaaaaaaaaaaaaaaaaaaaaaaaa",
    34  		"B7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajMUC",
    35  		"-dXsPJ3XDdzO3GLNqekTAmNfIXtE697vame6_4_HNUkC",
    36  		"ytsp2xXp26LpDqWLjKOUmpGorZXaEJGryJO1-Nkp5t0C",
    37  	}
    38  	for _, iid := range good {
    39  		Convey(fmt.Sprintf("Works with %q", iid), t, func() {
    40  			So(ValidateInstanceID(iid, KnownHash), ShouldBeNil)
    41  			So(ValidateInstanceID(iid, AnyHash), ShouldBeNil)
    42  		})
    43  	}
    44  
    45  	bad := []string{
    46  		"",
    47  		"€aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    48  		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    49  		"gaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    50  		"AAAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    51  		"B7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajM==", // no padding allowed
    52  		"/7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajMUC", // should be URL encoding, NOT std
    53  		"B7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajMUA", // unspecified hash algo
    54  		"AAAAAAAAAAAAAAAAAAAAAAAAAAAC",                 // bad digest len for an algo
    55  	}
    56  	for _, iid := range bad {
    57  		Convey(fmt.Sprintf("Fails with %q", iid), t, func() {
    58  			So(ValidateInstanceID(iid, KnownHash), ShouldNotBeNil)
    59  			So(ValidateInstanceID(iid, AnyHash), ShouldNotBeNil)
    60  		})
    61  	}
    62  
    63  	unknown := []string{
    64  		"B7r75joOfFfFcq7fHCKAIrU34oeFAT174Bf8eHMajMUD", // unrecognized hash algo
    65  		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",      // happens to be looking like unknown hash algo
    66  	}
    67  	for _, iid := range unknown {
    68  		Convey(fmt.Sprintf("Works with %q", iid), t, func() {
    69  			So(ValidateInstanceID(iid, KnownHash), ShouldNotBeNil)
    70  			So(ValidateInstanceID(iid, AnyHash), ShouldBeNil)
    71  		})
    72  	}
    73  }
    74  
    75  func TestValidateObjectRef(t *testing.T) {
    76  	t.Parallel()
    77  
    78  	Convey("SHA1", t, func() {
    79  		So(ValidateObjectRef(&api.ObjectRef{
    80  			HashAlgo:  api.HashAlgo_SHA1,
    81  			HexDigest: "0123456789abcdef0123456789abcdef00000000",
    82  		}, KnownHash), ShouldBeNil)
    83  
    84  		So(ValidateObjectRef(&api.ObjectRef{
    85  			HashAlgo:  api.HashAlgo_SHA1,
    86  			HexDigest: "abcd",
    87  		}, KnownHash), ShouldErrLike, "expecting 40 chars, got 4")
    88  
    89  		So(ValidateObjectRef(&api.ObjectRef{
    90  			HashAlgo:  api.HashAlgo_SHA1,
    91  			HexDigest: strings.Repeat("A", 40), // uppercase are forbidden
    92  		}, KnownHash), ShouldErrLike, "wrong char")
    93  	})
    94  
    95  	Convey("SHA256", t, func() {
    96  		So(ValidateObjectRef(&api.ObjectRef{
    97  			HashAlgo:  api.HashAlgo_SHA256,
    98  			HexDigest: "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447",
    99  		}, KnownHash), ShouldBeNil)
   100  
   101  		So(ValidateObjectRef(&api.ObjectRef{
   102  			HashAlgo:  api.HashAlgo_SHA256,
   103  			HexDigest: "abcd",
   104  		}, KnownHash), ShouldErrLike, "expecting 64 chars, got 4")
   105  
   106  		So(ValidateObjectRef(&api.ObjectRef{
   107  			HashAlgo:  api.HashAlgo_SHA256,
   108  			HexDigest: strings.Repeat("A", 64), // uppercase are forbidden
   109  		}, KnownHash), ShouldErrLike, "wrong char")
   110  	})
   111  
   112  	Convey("Some future hash in KnownHash mode", t, func() {
   113  		So(ValidateObjectRef(&api.ObjectRef{
   114  			HashAlgo:  33,
   115  			HexDigest: "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447",
   116  		}, KnownHash), ShouldErrLike, "unsupported hash algorithm 33")
   117  	})
   118  
   119  	Convey("Some future hash in AnyHash mode", t, func() {
   120  		So(ValidateObjectRef(&api.ObjectRef{
   121  			HashAlgo:  33,
   122  			HexDigest: "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447",
   123  		}, AnyHash), ShouldBeNil)
   124  
   125  		// Still checks that the hex digest looks like a digest.
   126  		So(ValidateObjectRef(&api.ObjectRef{
   127  			HashAlgo:  33,
   128  			HexDigest: "abc",
   129  		}, KnownHash), ShouldErrLike, "uneven number of symbols")
   130  
   131  		So(ValidateObjectRef(&api.ObjectRef{
   132  			HashAlgo:  33,
   133  			HexDigest: strings.Repeat("A", 64), // uppercase are forbidden
   134  		}, KnownHash), ShouldErrLike, "wrong char")
   135  	})
   136  
   137  	Convey("Bad args", t, func() {
   138  		So(ValidateObjectRef(nil, AnyHash), ShouldErrLike, "not provided")
   139  		So(ValidateObjectRef(&api.ObjectRef{HashAlgo: 0}, AnyHash), ShouldErrLike, "unspecified hash algo")
   140  	})
   141  }
   142  
   143  func TestRefIIDConversion(t *testing.T) {
   144  	t.Parallel()
   145  
   146  	Convey("SHA1 works", t, func() {
   147  		sha1hex := strings.Repeat("a", 40)
   148  		sha1iid := sha1hex // iid and hex digest coincide for SHA1
   149  
   150  		So(ObjectRefToInstanceID(&api.ObjectRef{
   151  			HashAlgo:  api.HashAlgo_SHA1,
   152  			HexDigest: sha1hex,
   153  		}), ShouldEqual, sha1iid)
   154  
   155  		So(InstanceIDToObjectRef(sha1iid), ShouldResembleProto, &api.ObjectRef{
   156  			HashAlgo:  api.HashAlgo_SHA1,
   157  			HexDigest: sha1hex,
   158  		})
   159  	})
   160  
   161  	Convey("SHA256 works", t, func() {
   162  		sha256hex := "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447"
   163  		sha256iid := "qUiQTy8PR5uPgZdpSzAYSw0u0cHNKh7A-4XSmaGSpEcC"
   164  
   165  		So(ObjectRefToInstanceID(&api.ObjectRef{
   166  			HashAlgo:  api.HashAlgo_SHA256,
   167  			HexDigest: sha256hex,
   168  		}), ShouldEqual, sha256iid)
   169  
   170  		So(InstanceIDToObjectRef(sha256iid), ShouldResembleProto, &api.ObjectRef{
   171  			HashAlgo:  api.HashAlgo_SHA256,
   172  			HexDigest: sha256hex,
   173  		})
   174  	})
   175  
   176  	Convey("Some future unknown hash", t, func() {
   177  		hex := strings.Repeat("a", 60)
   178  		iid := "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqIQ"
   179  
   180  		So(ObjectRefToInstanceID(&api.ObjectRef{
   181  			HashAlgo:  33,
   182  			HexDigest: hex,
   183  		}), ShouldEqual, iid)
   184  
   185  		So(InstanceIDToObjectRef(iid), ShouldResembleProto, &api.ObjectRef{
   186  			HashAlgo:  33,
   187  			HexDigest: hex,
   188  		})
   189  	})
   190  
   191  	Convey("Wrong length in InstanceIDToObjectRef", t, func() {
   192  		So(func() {
   193  			InstanceIDToObjectRef("aaaa")
   194  		}, ShouldPanicLike, "not a valid size for an encoded digest")
   195  	})
   196  
   197  	Convey("Bad format in InstanceIDToObjectRef", t, func() {
   198  		So(func() {
   199  			InstanceIDToObjectRef("qUiQTy8PR5uPgZdpSzAYSw0u0cHNKh7A-?XSmaGSpEcC")
   200  		}, ShouldPanicLike, "illegal base64 data")
   201  	})
   202  }