From 5671d803466badd32a5ef37d6758784e19b65826 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Tue, 3 Aug 2021 14:30:14 -0400 Subject: [PATCH 01/13] add type def for ETag --- sdk/azcore/core.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/azcore/core.go b/sdk/azcore/core.go index ff915e59eae3..b30a1bb2f374 100644 --- a/sdk/azcore/core.go +++ b/sdk/azcore/core.go @@ -203,3 +203,6 @@ func IsNullValue(v interface{}) bool { // no sentinel object for this *t return false } + +// ETag is a property used for optimistic concurrency during updates +type ETag string From bd1dfcd637bcab6936ad7d4a937bde15ba93f036 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Thu, 5 Aug 2021 13:47:22 -0400 Subject: [PATCH 02/13] adding etag specific files and more functionality --- sdk/azcore/core.go | 5 +---- sdk/azcore/etag.go | 41 +++++++++++++++++++++++++++++++++++++++++ sdk/azcore/etag_test.go | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 sdk/azcore/etag.go create mode 100644 sdk/azcore/etag_test.go diff --git a/sdk/azcore/core.go b/sdk/azcore/core.go index b30a1bb2f374..1219c5f419c8 100644 --- a/sdk/azcore/core.go +++ b/sdk/azcore/core.go @@ -202,7 +202,4 @@ func IsNullValue(v interface{}) bool { } // no sentinel object for this *t return false -} - -// ETag is a property used for optimistic concurrency during updates -type ETag string +} \ No newline at end of file diff --git a/sdk/azcore/etag.go b/sdk/azcore/etag.go new file mode 100644 index 000000000000..07e9e7fcac82 --- /dev/null +++ b/sdk/azcore/etag.go @@ -0,0 +1,41 @@ +// +build go1.13 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package azcore + +import ( + "strings" +) + +// ETag is a property used for optimistic concurrency during updates +type ETag struct { + value *string +} + +func NewEtag(value string) *ETag { + return &ETag{value: &value} +} + +func (e ETag) Equals(right ETag) bool { + // ETags are != if one value is null + if *e.value == "" || *right.value == "" { + // If both are null, they are considered equal + return *e.value == *right.value + } + + return true +} + +func (e ETag) String() string { + return *e.value +} + +func (e ETag) HasValue() bool { + return e.value != nil +} + +func (e ETag) IsWeak() bool { + return e.value != nil && len(*e.value) >= 4 && strings.HasPrefix(*e.value, "W/\"") && strings.HasSuffix(*e.value, "\"") +} diff --git a/sdk/azcore/etag_test.go b/sdk/azcore/etag_test.go new file mode 100644 index 000000000000..497c583a6207 --- /dev/null +++ b/sdk/azcore/etag_test.go @@ -0,0 +1,37 @@ +// +build go1.13 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package azcore + +import "testing" + +func TestEtagEquals(t *testing.T) { + e1 := NewEtag("tag") + if e1.String() != "tag" { + t.Fatalf("ETag values are not equal") + } + + e2 := NewEtag("\"tag\"") + if e2.String() != "\"tag\"" { + t.Fatalf("ETag values are not equal") + } + + e3 := NewEtag("W/\"weakETag\"") + if e3.String() != "W/\"weakETag\"" { + t.Fatalf("ETag values are not equal") + } + if !e3.IsWeak() { + t.Fatalf("ETag is expected to be weak") + } + + strongETag := NewEtag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + if strongETag.String() != "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"" { + t.Fatalf("Etag values are not equal") + } +} + +func TestEtagWeak(t *testing.T) { + +} \ No newline at end of file From 8e0a9f95a34bc407ccfadaa1beb0c5cd4b8bd217 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Thu, 5 Aug 2021 15:20:16 -0400 Subject: [PATCH 03/13] testing weak --- sdk/azcore/etag.go | 39 +++++++++++++++-- sdk/azcore/etag_test.go | 92 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 120 insertions(+), 11 deletions(-) diff --git a/sdk/azcore/etag.go b/sdk/azcore/etag.go index 07e9e7fcac82..15d0a4c7b16d 100644 --- a/sdk/azcore/etag.go +++ b/sdk/azcore/etag.go @@ -14,18 +14,42 @@ type ETag struct { value *string } -func NewEtag(value string) *ETag { +func NewETag(value string) *ETag { return &ETag{value: &value} } -func (e ETag) Equals(right ETag) bool { +type ComparisonType string + +const ( + Strong ComparisonType = "strong" + WeakComparison ComparisonType = "weak" +) + +func (e ETag) Equals(right ETag, comparisonKind ComparisonType) bool { // ETags are != if one value is null if *e.value == "" || *right.value == "" { // If both are null, they are considered equal return *e.value == *right.value } - return true + if comparisonKind == Strong { + return !e.IsWeak() && right.IsWeak() && *e.value == *right.value + } + + leftStart := e.getStart() + rightStart := right.getStart() + + leftValue := (*e.value)[leftStart:] + rightValue := (*e.value)[rightStart:] + + return leftValue == rightValue +} + +func (e ETag) getStart() int { + if e.IsWeak() { + return 2 + } + return 0 } func (e ETag) String() string { @@ -37,5 +61,14 @@ func (e ETag) HasValue() bool { } func (e ETag) IsWeak() bool { + // fmt.Println(e.value != nil) + // fmt.Println(len(*e.value) >= 4) + // fmt.Println(strings.HasPrefix(*e.value, "W/\"")) + // fmt.Println(strings.HasSuffix(*e.value, "\"")) return e.value != nil && len(*e.value) >= 4 && strings.HasPrefix(*e.value, "W/\"") && strings.HasSuffix(*e.value, "\"") } + +func ETagAny() *ETag { + any := "*" + return &ETag{value: &any} +} diff --git a/sdk/azcore/etag_test.go b/sdk/azcore/etag_test.go index 497c583a6207..e6953671fe5f 100644 --- a/sdk/azcore/etag_test.go +++ b/sdk/azcore/etag_test.go @@ -5,20 +5,23 @@ package azcore -import "testing" +import ( + "fmt" + "testing" +) func TestEtagEquals(t *testing.T) { - e1 := NewEtag("tag") + e1 := NewETag("tag") if e1.String() != "tag" { t.Fatalf("ETag values are not equal") } - e2 := NewEtag("\"tag\"") + e2 := NewETag("\"tag\"") if e2.String() != "\"tag\"" { t.Fatalf("ETag values are not equal") } - e3 := NewEtag("W/\"weakETag\"") + e3 := NewETag("W/\"weakETag\"") if e3.String() != "W/\"weakETag\"" { t.Fatalf("ETag values are not equal") } @@ -26,12 +29,85 @@ func TestEtagEquals(t *testing.T) { t.Fatalf("ETag is expected to be weak") } - strongETag := NewEtag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + strongETag := NewETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") if strongETag.String() != "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"" { t.Fatalf("Etag values are not equal") } + + if ETagAny().IsWeak() { + t.Fatalf("ETagAny should not be weak") + } } -func TestEtagWeak(t *testing.T) { - -} \ No newline at end of file +func TestETagWeak(t *testing.T) { + et1 := NewETag("tag") + if !et1.IsWeak() { + t.Fatalf("Expected to be weak") + } + + et2 := NewETag("\"tag\"") + if !et2.IsWeak() { + t.Fatalf("Expected to be weak") + } + + et3 := NewETag("W/\"weakETag\"") + if !et3.IsWeak() { + t.Fatalf("Expected to be weak") + } + + et4 := NewETag("W/\"\"") + if !et4.IsWeak() { + t.Fatalf("Expected to be weak") + } + + et5 := ETagAny() + if !et5.IsWeak() { + t.Fatalf("Expected to be weak") + } +} + +/* + +func TestEtagStars(t *testing.T) { + anyETag := ETagAny() + star := NewETag("*") + // weakStar := NewETag("W\"*\"") + quotedStar := NewETag("\"*\"") + + strongETag := NewETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + + if anyETag.Equals(*anyETag, Strong) { + t.Fatalf("Expected etags to be equal") + } + if anyETag.Equals(*ETagAny(), Strong) { + t.Fatalf("Expected etags to be equal") + } + if anyETag.Equals(*strongETag, Strong) { + t.Fatalf("Expected etags to be equal") + } + + // expectEqual(t, star, star) + // expectEqual(t, star, ETagAny()) + // expectEqual(t, star, anyETag) + + // expectNotEqual(t, star, weakStar) + // expectNotEqual(t, weakStar, ETagAny()) + // expectNotEqual(t, quotedStar, weakStar) + + expectNotEqual(t, star, quotedStar) + expectEqual(t, anyETag, star) +} +*/ + +func expectEqual(t *testing.T, left *ETag, right *ETag) { + if !left.Equals(*right, Strong) { + fmt.Println(*left.value, *right.value) + t.Fatalf("Expected etags to be equal") + } +} + +func expectNotEqual(t *testing.T, left *ETag, right *ETag) { + if left.Equals(*right, Strong) { + t.Fatalf("Expected etags to not be equal") + } +} From 0390d0092b06e40bae0757037e0d68a5caa15d28 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Thu, 5 Aug 2021 15:34:28 -0400 Subject: [PATCH 04/13] testing for etag equality --- sdk/azcore/etag.go | 2 +- sdk/azcore/etag_test.go | 69 +++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/sdk/azcore/etag.go b/sdk/azcore/etag.go index 15d0a4c7b16d..61e978bd3e06 100644 --- a/sdk/azcore/etag.go +++ b/sdk/azcore/etag.go @@ -33,7 +33,7 @@ func (e ETag) Equals(right ETag, comparisonKind ComparisonType) bool { } if comparisonKind == Strong { - return !e.IsWeak() && right.IsWeak() && *e.value == *right.value + return !e.IsWeak() && !right.IsWeak() && *e.value == *right.value } leftStart := e.getStart() diff --git a/sdk/azcore/etag_test.go b/sdk/azcore/etag_test.go index e6953671fe5f..1767e461d41e 100644 --- a/sdk/azcore/etag_test.go +++ b/sdk/azcore/etag_test.go @@ -66,48 +66,51 @@ func TestETagWeak(t *testing.T) { } } -/* - -func TestEtagStars(t *testing.T) { - anyETag := ETagAny() - star := NewETag("*") - // weakStar := NewETag("W\"*\"") - quotedStar := NewETag("\"*\"") - - strongETag := NewETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") - - if anyETag.Equals(*anyETag, Strong) { +func TestEtagEquality(t *testing.T) { + weakTag := NewETag("W/\"\"") + weakTag1 := NewETag("W/\"1\"") + weakTag2 := NewETag("W/\"Two\"") + strongTag1 := NewETag("\"1\"") + strongTag2 := NewETag("\"Two\"") + strongTagValidChars := NewETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + weakTagValidChars := NewETag("W/\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + + if weakTag.Equals(*weakTag, Strong) { + t.Fatalf("Expected etags to not be equal") + } + if weakTag1.Equals(*weakTag1, Strong) { + t.Fatalf("Expected etags to not be equal") + } + if weakTag2.Equals(*weakTag2, Strong) { + t.Fatalf("Expected etags to not be equal") + } + if weakTagValidChars.Equals(*weakTagValidChars, Strong) { + t.Fatalf("Expected etags to not be equal") + } + if !strongTag1.Equals(*strongTag1, Strong) { t.Fatalf("Expected etags to be equal") } - if anyETag.Equals(*ETagAny(), Strong) { + if !strongTag2.Equals(*strongTag2, Strong) { t.Fatalf("Expected etags to be equal") } - if anyETag.Equals(*strongETag, Strong) { + if !strongTagValidChars.Equals(*strongTagValidChars, Strong) { t.Fatalf("Expected etags to be equal") } - // expectEqual(t, star, star) - // expectEqual(t, star, ETagAny()) - // expectEqual(t, star, anyETag) - - // expectNotEqual(t, star, weakStar) - // expectNotEqual(t, weakStar, ETagAny()) - // expectNotEqual(t, quotedStar, weakStar) - - expectNotEqual(t, star, quotedStar) - expectEqual(t, anyETag, star) -} -*/ - -func expectEqual(t *testing.T, left *ETag, right *ETag) { - if !left.Equals(*right, Strong) { - fmt.Println(*left.value, *right.value) - t.Fatalf("Expected etags to be equal") + if weakTag.Equals(*weakTag1, Strong) { + t.Fatalf("Expected etags to not be equal") + } + if weakTagValidChars.Equals(*strongTagValidChars, Strong) { + t.Fatalf("Expected etags to not be equal") } -} -func expectNotEqual(t *testing.T, left *ETag, right *ETag) { - if left.Equals(*right, Strong) { + if weakTag1.Equals(*weakTag2, Strong) { + t.Fatalf("Expected etags to not be equal") + } + if weakTag1.Equals(*strongTag1, Strong) { + t.Fatalf("Expected etags to not be equal") + } + if weakTag2.Equals(*strongTag2, Strong) { t.Fatalf("Expected etags to not be equal") } } From 2f48548b0f934748d93a6443dbfe8da96da2fd80 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Thu, 5 Aug 2021 15:58:22 -0400 Subject: [PATCH 05/13] weak tag comparisons --- sdk/azcore/etag.go | 7 +-- sdk/azcore/etag_test.go | 110 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 4 deletions(-) diff --git a/sdk/azcore/etag.go b/sdk/azcore/etag.go index 61e978bd3e06..1a3e1003d60c 100644 --- a/sdk/azcore/etag.go +++ b/sdk/azcore/etag.go @@ -6,6 +6,7 @@ package azcore import ( + "fmt" "strings" ) @@ -21,8 +22,8 @@ func NewETag(value string) *ETag { type ComparisonType string const ( - Strong ComparisonType = "strong" - WeakComparison ComparisonType = "weak" + Strong ComparisonType = "strong" + Weak ComparisonType = "weak" ) func (e ETag) Equals(right ETag, comparisonKind ComparisonType) bool { @@ -40,7 +41,7 @@ func (e ETag) Equals(right ETag, comparisonKind ComparisonType) bool { rightStart := right.getStart() leftValue := (*e.value)[leftStart:] - rightValue := (*e.value)[rightStart:] + rightValue := (*right.value)[rightStart:] return leftValue == rightValue } diff --git a/sdk/azcore/etag_test.go b/sdk/azcore/etag_test.go index 1767e461d41e..755184f6cc59 100644 --- a/sdk/azcore/etag_test.go +++ b/sdk/azcore/etag_test.go @@ -6,7 +6,6 @@ package azcore import ( - "fmt" "testing" ) @@ -114,3 +113,112 @@ func TestEtagEquality(t *testing.T) { t.Fatalf("Expected etags to not be equal") } } + +func TestEtagAny(t *testing.T) { + anyETag := ETagAny() + star := NewETag("*") + weakStar := NewETag("W\"*\"") + quotedStart := NewETag("\"*\"") + + if !anyETag.Equals(*anyETag, Strong) { + t.Fatalf("Expected etags to be equal") + } + if !anyETag.Equals(*ETagAny(), Strong) { + t.Fatalf("Expected etags to be equal") + } + + if !star.Equals(*star, Strong) { + t.Fatalf("Expected etags to be equal") + } + if !star.Equals(*ETagAny(), Strong) { + t.Fatalf("Expected etags to be equal") + } + if !star.Equals(*anyETag, Strong) { + t.Fatalf("Expected etags to be equal") + } + + if star.Equals(*weakStar, Strong) { + t.Fatalf("Expected etags to not be equal") + } + if weakStar.Equals(*ETagAny(), Strong) { + t.Fatalf("Expected etags to not be equal") + } + if quotedStart.Equals(*weakStar, Strong) { + t.Fatalf("Expected etags to not be equal") + } + + + if star.Equals(*quotedStart, Strong) { + t.Fatalf("Expected etags to not be equal") + } + if !ETagAny().Equals(*star, Strong) { + t.Fatalf("Expected etags to not be equal") + } +} + +func TestEtagWeakComparison(t *testing.T) { + // W/"" + weakTag := NewETag("W/\"\""); + // W/"1" + weakTag1 := NewETag("W/\"1\""); + // W/"Two" + weakTagTwo := NewETag("W/\"Two\""); + // W/"two" + weakTagtwo := NewETag("W/\"two\""); + // "1" + strongTag1 := NewETag("\"1\""); + // "Two" + strongTagTwo := NewETag("\"Two\""); + // "two" + strongTagtwo := NewETag("\"two\""); + + if !weakTag.Equals(*weakTag, Weak) { + t.Fatalf("Expected etags to be equal") + } + if !weakTag1.Equals(*weakTag1, Weak) { + t.Fatalf("Expected etags to be equal") + } + if !weakTagTwo.Equals(*weakTagTwo, Weak) { + t.Fatalf("Expected etags to be equal") + } + if !weakTagtwo.Equals(*weakTagtwo, Weak) { + t.Fatalf("Expected etags to be equal") + } + if !strongTag1.Equals(*strongTag1, Weak) { + t.Fatalf("Expected etags to be equal") + } + if !strongTagTwo.Equals(*strongTagTwo, Weak) { + t.Fatalf("Expected etags to be equal") + } + if !strongTagtwo.Equals(*strongTagtwo, Weak) { + t.Fatalf("Expected etags to be equal") + } + + if weakTag.Equals(*weakTag1, Weak) { + t.Fatalf("Expected etags to not be equal") + } + if weakTag1.Equals(*weakTagTwo, Weak) { + t.Fatalf("Expected etags to not be equal") + } + + if !weakTag1.Equals(*strongTag1, Weak) { + t.Fatalf("Expected etags to be equal") + } + if !weakTagTwo.Equals(*strongTagTwo, Weak) { + t.Fatalf("Expected etags to be equal") + } + + if strongTagTwo.Equals(*weakTag1, Weak) { + t.Fatalf("Expected etags to not be equal") + } + if strongTagTwo.Equals(*weakTagtwo, Weak) { + t.Fatalf("Expected etags to not be equal") + } + + if strongTagTwo.Equals(*strongTagtwo, Weak) { + t.Fatalf("Expected etags to not be equal") + } + if weakTagTwo.Equals(*weakTagtwo, Weak) { + t.Fatalf("Expected etags to not be equal") + } +} From cbad20c209c65315a026b53df0eb65ab96e63473 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Thu, 5 Aug 2021 16:07:08 -0400 Subject: [PATCH 06/13] adding docstrings --- sdk/azcore/etag.go | 15 ++++++++++----- sdk/azcore/etag_test.go | 6 +++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/sdk/azcore/etag.go b/sdk/azcore/etag.go index 1a3e1003d60c..e6ff1de65da9 100644 --- a/sdk/azcore/etag.go +++ b/sdk/azcore/etag.go @@ -6,19 +6,21 @@ package azcore import ( - "fmt" "strings" ) // ETag is a property used for optimistic concurrency during updates +// ETag is a validator based on https://tools.ietf.org/html/rfc7232#section-2.3.2 type ETag struct { value *string } +// NewETag creates a new ETag struct func NewETag(value string) *ETag { return &ETag{value: &value} } +// ComparisonType specifies what type of comparison to use, Strong or Weak type ComparisonType string const ( @@ -26,6 +28,9 @@ const ( Weak ComparisonType = "weak" ) +// Equals determines whether two entity-tags are equal. There are two types of comparison: Strong and Weak. +// Strong comparison: two ETags are equivalent if both are not weak and their opaque-tags match character-by-character +// Weak Comparison: two ETags are equivalent if their opaque-tags match character-by-character regardless of either or both being tagged as "weak" func (e ETag) Equals(right ETag, comparisonKind ComparisonType) bool { // ETags are != if one value is null if *e.value == "" || *right.value == "" { @@ -53,22 +58,22 @@ func (e ETag) getStart() int { return 0 } +// String returns a string representation of an ETag func (e ETag) String() string { return *e.value } +// HasValue returns whether an ETag is present func (e ETag) HasValue() bool { return e.value != nil } +// IsWeak specifies whether the ETag is strong or weak. func (e ETag) IsWeak() bool { - // fmt.Println(e.value != nil) - // fmt.Println(len(*e.value) >= 4) - // fmt.Println(strings.HasPrefix(*e.value, "W/\"")) - // fmt.Println(strings.HasSuffix(*e.value, "\"")) return e.value != nil && len(*e.value) >= 4 && strings.HasPrefix(*e.value, "W/\"") && strings.HasSuffix(*e.value, "\"") } +// ETagAny returns a new ETag that represents everything, the value is "*" func ETagAny() *ETag { any := "*" return &ETag{value: &any} diff --git a/sdk/azcore/etag_test.go b/sdk/azcore/etag_test.go index 755184f6cc59..bd4b9c986d22 100644 --- a/sdk/azcore/etag_test.go +++ b/sdk/azcore/etag_test.go @@ -40,12 +40,12 @@ func TestEtagEquals(t *testing.T) { func TestETagWeak(t *testing.T) { et1 := NewETag("tag") - if !et1.IsWeak() { + if et1.IsWeak() { t.Fatalf("Expected to be weak") } et2 := NewETag("\"tag\"") - if !et2.IsWeak() { + if et2.IsWeak() { t.Fatalf("Expected to be weak") } @@ -60,7 +60,7 @@ func TestETagWeak(t *testing.T) { } et5 := ETagAny() - if !et5.IsWeak() { + if et5.IsWeak() { t.Fatalf("Expected to be weak") } } From 24803fd8ae9b761f7e549f46881c8557bc0e2c4e Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Fri, 6 Aug 2021 12:19:50 -0400 Subject: [PATCH 07/13] addressing richard and jeffs feedback. split equals to strong and weak, using more HasValue throughout --- sdk/azcore/etag.go | 77 ++++------- sdk/azcore/etag_test.go | 293 ++++++++++++++-------------------------- sdk/azcore/go.mod | 1 + sdk/azcore/go.sum | 4 + 4 files changed, 135 insertions(+), 240 deletions(-) diff --git a/sdk/azcore/etag.go b/sdk/azcore/etag.go index e6ff1de65da9..92b3afc22b57 100644 --- a/sdk/azcore/etag.go +++ b/sdk/azcore/etag.go @@ -11,70 +11,51 @@ import ( // ETag is a property used for optimistic concurrency during updates // ETag is a validator based on https://tools.ietf.org/html/rfc7232#section-2.3.2 -type ETag struct { - value *string -} +type ETag *string -// NewETag creates a new ETag struct -func NewETag(value string) *ETag { - return &ETag{value: &value} +// StrongEquals does a strong comparison of two ETags. StrongEquals returns true when both +// ETags are not weak and the values of the underlying strings are equal. If both ETags are "nil" they are considered equal +func StrongEquals(a, b ETag) bool { + if !HasValue(a) || !HasValue(b) { + return a == b + } + return !IsWeak(a) && !IsWeak(b) && *a == *b } -// ComparisonType specifies what type of comparison to use, Strong or Weak -type ComparisonType string - -const ( - Strong ComparisonType = "strong" - Weak ComparisonType = "weak" -) - -// Equals determines whether two entity-tags are equal. There are two types of comparison: Strong and Weak. -// Strong comparison: two ETags are equivalent if both are not weak and their opaque-tags match character-by-character -// Weak Comparison: two ETags are equivalent if their opaque-tags match character-by-character regardless of either or both being tagged as "weak" -func (e ETag) Equals(right ETag, comparisonKind ComparisonType) bool { - // ETags are != if one value is null - if *e.value == "" || *right.value == "" { - // If both are null, they are considered equal - return *e.value == *right.value +// WeakEquals does a weak compariosn of two ETags. Two ETags are equivalent if their opaque-tags match +// character-by-character, regardless of either or both being tagged as "weak". If both ETags are "nil" they are considered equal +func WeakEquals(a, b ETag) bool { + if !HasValue(a) || !HasValue(b) { + return a == b } - if comparisonKind == Strong { - return !e.IsWeak() && !right.IsWeak() && *e.value == *right.value + getStart := func(e ETag) int { + if IsWeak(e) { + return 2 + } + return 0 } + aStart := getStart(a) + bStart := getStart(b) - leftStart := e.getStart() - rightStart := right.getStart() - - leftValue := (*e.value)[leftStart:] - rightValue := (*right.value)[rightStart:] - - return leftValue == rightValue -} - -func (e ETag) getStart() int { - if e.IsWeak() { - return 2 - } - return 0 -} + aVal := (*a)[aStart:] + bVal := (*b)[bStart:] -// String returns a string representation of an ETag -func (e ETag) String() string { - return *e.value + return aVal == bVal } // HasValue returns whether an ETag is present -func (e ETag) HasValue() bool { - return e.value != nil +func HasValue(e ETag) bool { + return e != nil } // IsWeak specifies whether the ETag is strong or weak. -func (e ETag) IsWeak() bool { - return e.value != nil && len(*e.value) >= 4 && strings.HasPrefix(*e.value, "W/\"") && strings.HasSuffix(*e.value, "\"") +func IsWeak(e ETag) bool { + return HasValue(e) && len(*e) >= 4 && strings.HasPrefix(*e, "W/\"") && strings.HasSuffix(*e, "\"") } // ETagAny returns a new ETag that represents everything, the value is "*" -func ETagAny() *ETag { +func ETagAny() ETag { any := "*" - return &ETag{value: &any} + return ETag(&any) } diff --git a/sdk/azcore/etag_test.go b/sdk/azcore/etag_test.go index bd4b9c986d22..c71880dc4167 100644 --- a/sdk/azcore/etag_test.go +++ b/sdk/azcore/etag_test.go @@ -7,218 +7,127 @@ package azcore import ( "testing" + + "github.com/stretchr/testify/require" ) -func TestEtagEquals(t *testing.T) { - e1 := NewETag("tag") - if e1.String() != "tag" { - t.Fatalf("ETag values are not equal") - } - - e2 := NewETag("\"tag\"") - if e2.String() != "\"tag\"" { - t.Fatalf("ETag values are not equal") - } - - e3 := NewETag("W/\"weakETag\"") - if e3.String() != "W/\"weakETag\"" { - t.Fatalf("ETag values are not equal") - } - if !e3.IsWeak() { - t.Fatalf("ETag is expected to be weak") - } - - strongETag := NewETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") - if strongETag.String() != "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"" { - t.Fatalf("Etag values are not equal") - } - - if ETagAny().IsWeak() { - t.Fatalf("ETagAny should not be weak") - } +func createETag(s string) ETag { + return ETag(&s) +} + +func TestETagEquals(t *testing.T) { + e1 := createETag("tag") + require.Equal(t, *e1, "tag") + + e2 := createETag("\"tag\"") + require.Equal(t, *e2, "\"tag\"") + + e3 := createETag("W/\"weakETag\"") + require.Equal(t, *e3, "W/\"weakETag\"") + require.Truef(t, IsWeak(e3), "ETag is ecpected to be weak") + + strongETag := createETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + require.Equal(t, *strongETag, "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + + require.Falsef(t, IsWeak(ETagAny()), "ETagAny should not be weak") } func TestETagWeak(t *testing.T) { - et1 := NewETag("tag") - if et1.IsWeak() { - t.Fatalf("Expected to be weak") - } - - et2 := NewETag("\"tag\"") - if et2.IsWeak() { - t.Fatalf("Expected to be weak") - } - - et3 := NewETag("W/\"weakETag\"") - if !et3.IsWeak() { - t.Fatalf("Expected to be weak") - } - - et4 := NewETag("W/\"\"") - if !et4.IsWeak() { - t.Fatalf("Expected to be weak") - } + et1 := createETag("tag") + require.Falsef(t, IsWeak(et1), "expected etag to be strong") + + et2 := createETag("\"tag\"") + require.Falsef(t, IsWeak(et2), "expected etag to be strong") + + et3 := createETag("W/\"weakETag\"") + require.Truef(t, IsWeak(et3), "expected etag to be weak") + + et4 := createETag("W/\"\"") + require.Truef(t, IsWeak(et4), "expected etag to be weak") et5 := ETagAny() - if et5.IsWeak() { - t.Fatalf("Expected to be weak") - } + require.Falsef(t, IsWeak(et5), "expected etag to be strong") } -func TestEtagEquality(t *testing.T) { - weakTag := NewETag("W/\"\"") - weakTag1 := NewETag("W/\"1\"") - weakTag2 := NewETag("W/\"Two\"") - strongTag1 := NewETag("\"1\"") - strongTag2 := NewETag("\"Two\"") - strongTagValidChars := NewETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") - weakTagValidChars := NewETag("W/\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") - - if weakTag.Equals(*weakTag, Strong) { - t.Fatalf("Expected etags to not be equal") - } - if weakTag1.Equals(*weakTag1, Strong) { - t.Fatalf("Expected etags to not be equal") - } - if weakTag2.Equals(*weakTag2, Strong) { - t.Fatalf("Expected etags to not be equal") - } - if weakTagValidChars.Equals(*weakTagValidChars, Strong) { - t.Fatalf("Expected etags to not be equal") - } - if !strongTag1.Equals(*strongTag1, Strong) { - t.Fatalf("Expected etags to be equal") - } - if !strongTag2.Equals(*strongTag2, Strong) { - t.Fatalf("Expected etags to be equal") - } - if !strongTagValidChars.Equals(*strongTagValidChars, Strong) { - t.Fatalf("Expected etags to be equal") - } - - if weakTag.Equals(*weakTag1, Strong) { - t.Fatalf("Expected etags to not be equal") - } - if weakTagValidChars.Equals(*strongTagValidChars, Strong) { - t.Fatalf("Expected etags to not be equal") - } - - if weakTag1.Equals(*weakTag2, Strong) { - t.Fatalf("Expected etags to not be equal") - } - if weakTag1.Equals(*strongTag1, Strong) { - t.Fatalf("Expected etags to not be equal") - } - if weakTag2.Equals(*strongTag2, Strong) { - t.Fatalf("Expected etags to not be equal") - } +func TestETagEquality(t *testing.T) { + weakTag := createETag("W/\"\"") + weakTag1 := createETag("W/\"1\"") + weakTag2 := createETag("W/\"Two\"") + strongTag1 := createETag("\"1\"") + strongTag2 := createETag("\"Two\"") + strongTagValidChars := createETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + weakTagValidChars := createETag("W/\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + + require.Falsef(t, StrongEquals(weakTag, weakTag), "Expected etags to not be equal") + require.Falsef(t, StrongEquals(weakTag1, weakTag1), "Expected etags to not be equal") + require.Falsef(t, StrongEquals(weakTag2, weakTag2), "Expected etags to not be equal") + require.Falsef(t, StrongEquals(weakTagValidChars, weakTagValidChars), "Expected etags to not be equal") + + require.Truef(t, StrongEquals(strongTag1, strongTag1), "Expected etags to be equal") + require.Truef(t, StrongEquals(strongTag2, strongTag2), "Expected etags to be equal") + require.Truef(t, StrongEquals(strongTagValidChars, strongTagValidChars), "Expected etags to be equal") + + require.Falsef(t, StrongEquals(weakTag, weakTag1), "Expected etags to not be equal") + require.Falsef(t, StrongEquals(weakTagValidChars, strongTagValidChars), "Expected etags to not be equal") + require.Falsef(t, StrongEquals(weakTag1, weakTag2), "Expected etags to not be equal") + require.Falsef(t, StrongEquals(weakTag1, strongTag1), "Expected etags to not be equal") + require.Falsef(t, StrongEquals(weakTag2, strongTag2), "Expected etags to not be equal") } func TestEtagAny(t *testing.T) { anyETag := ETagAny() - star := NewETag("*") - weakStar := NewETag("W\"*\"") - quotedStart := NewETag("\"*\"") - - if !anyETag.Equals(*anyETag, Strong) { - t.Fatalf("Expected etags to be equal") - } - if !anyETag.Equals(*ETagAny(), Strong) { - t.Fatalf("Expected etags to be equal") - } - - if !star.Equals(*star, Strong) { - t.Fatalf("Expected etags to be equal") - } - if !star.Equals(*ETagAny(), Strong) { - t.Fatalf("Expected etags to be equal") - } - if !star.Equals(*anyETag, Strong) { - t.Fatalf("Expected etags to be equal") - } - - if star.Equals(*weakStar, Strong) { - t.Fatalf("Expected etags to not be equal") - } - if weakStar.Equals(*ETagAny(), Strong) { - t.Fatalf("Expected etags to not be equal") - } - if quotedStart.Equals(*weakStar, Strong) { - t.Fatalf("Expected etags to not be equal") - } - - - if star.Equals(*quotedStart, Strong) { - t.Fatalf("Expected etags to not be equal") - } - if !ETagAny().Equals(*star, Strong) { - t.Fatalf("Expected etags to not be equal") - } + star := createETag("*") + weakStar := createETag("W\"*\"") + quotedStart := createETag("\"*\"") + + require.Truef(t, StrongEquals(anyETag, anyETag), "Expected etags to be equal") + require.Truef(t, StrongEquals(anyETag, ETagAny()), "Expected etags to be equal") + + require.Truef(t, StrongEquals(star, star), "Expected etags to be equal") + require.Truef(t, StrongEquals(star, ETagAny()), "Expected etags to be equal") + require.Truef(t, StrongEquals(star, anyETag), "Expected etags to be equal") + + require.Falsef(t, StrongEquals(weakStar, star), "Expected etags to be equal") + require.Falsef(t, StrongEquals(weakStar, ETagAny()), "Expected etags to be equal") + require.Falsef(t, StrongEquals(quotedStart, weakStar), "Expected etags to be equal") + + require.Falsef(t, StrongEquals(star, quotedStart), "Expected etags to be equal") + require.Falsef(t, StrongEquals(ETagAny(), star), "Expected etags to be equal") } -func TestEtagWeakComparison(t *testing.T) { +func TestETagWeakComparison(t *testing.T) { // W/"" - weakTag := NewETag("W/\"\""); + weakTag := createETag("W/\"\"") // W/"1" - weakTag1 := NewETag("W/\"1\""); + weakTag1 := createETag("W/\"1\"") // W/"Two" - weakTagTwo := NewETag("W/\"Two\""); + weakTagTwo := createETag("W/\"Two\"") // W/"two" - weakTagtwo := NewETag("W/\"two\""); + weakTagtwo := createETag("W/\"two\"") // "1" - strongTag1 := NewETag("\"1\""); + strongTag1 := createETag("\"1\"") // "Two" - strongTagTwo := NewETag("\"Two\""); + strongTagTwo := createETag("\"Two\"") // "two" - strongTagtwo := NewETag("\"two\""); - - if !weakTag.Equals(*weakTag, Weak) { - t.Fatalf("Expected etags to be equal") - } - if !weakTag1.Equals(*weakTag1, Weak) { - t.Fatalf("Expected etags to be equal") - } - if !weakTagTwo.Equals(*weakTagTwo, Weak) { - t.Fatalf("Expected etags to be equal") - } - if !weakTagtwo.Equals(*weakTagtwo, Weak) { - t.Fatalf("Expected etags to be equal") - } - if !strongTag1.Equals(*strongTag1, Weak) { - t.Fatalf("Expected etags to be equal") - } - if !strongTagTwo.Equals(*strongTagTwo, Weak) { - t.Fatalf("Expected etags to be equal") - } - if !strongTagtwo.Equals(*strongTagtwo, Weak) { - t.Fatalf("Expected etags to be equal") - } - - if weakTag.Equals(*weakTag1, Weak) { - t.Fatalf("Expected etags to not be equal") - } - if weakTag1.Equals(*weakTagTwo, Weak) { - t.Fatalf("Expected etags to not be equal") - } - - if !weakTag1.Equals(*strongTag1, Weak) { - t.Fatalf("Expected etags to be equal") - } - if !weakTagTwo.Equals(*strongTagTwo, Weak) { - t.Fatalf("Expected etags to be equal") - } - - if strongTagTwo.Equals(*weakTag1, Weak) { - t.Fatalf("Expected etags to not be equal") - } - if strongTagTwo.Equals(*weakTagtwo, Weak) { - t.Fatalf("Expected etags to not be equal") - } - - if strongTagTwo.Equals(*strongTagtwo, Weak) { - t.Fatalf("Expected etags to not be equal") - } - if weakTagTwo.Equals(*weakTagtwo, Weak) { - t.Fatalf("Expected etags to not be equal") - } + strongTagtwo := createETag("\"two\"") + + require.Truef(t, WeakEquals(weakTag, weakTag), "expected etags to be equal") + require.Truef(t, WeakEquals(weakTag1, weakTag1), "expected etags to be equal") + require.Truef(t, WeakEquals(weakTagTwo, weakTagTwo), "expected etags to be equal") + require.Truef(t, WeakEquals(weakTagtwo, weakTagtwo), "expected etags to be equal") + require.Truef(t, WeakEquals(strongTag1, strongTag1), "expected etags to be equal") + require.Truef(t, WeakEquals(strongTagTwo, strongTagTwo), "expected etags to be equal") + require.Truef(t, WeakEquals(strongTagtwo, strongTagtwo), "expected etags to be equal") + + require.Falsef(t, WeakEquals(weakTag, weakTag1), "Expected etags to not be equal") + require.Falsef(t, WeakEquals(weakTag1, weakTagTwo), "Expected etags to not be equal") + + require.Truef(t, WeakEquals(weakTag1, strongTag1), "expected etags to be equal") + require.Truef(t, WeakEquals(weakTagTwo, strongTagTwo), "expected etags to be equal") + + require.Falsef(t, WeakEquals(strongTagTwo, weakTag1), "Expected etags to not be equal") + require.Falsef(t, WeakEquals(strongTagTwo, weakTagtwo), "Expected etags to not be equal") + + require.Falsef(t, WeakEquals(strongTagTwo, strongTagtwo), "Expected etags to not be equal") + require.Falsef(t, WeakEquals(weakTagTwo, weakTagtwo), "Expected etags to not be equal") } diff --git a/sdk/azcore/go.mod b/sdk/azcore/go.mod index db8caa57b4fe..d1352741ce9c 100644 --- a/sdk/azcore/go.mod +++ b/sdk/azcore/go.mod @@ -2,6 +2,7 @@ module github.com/Azure/azure-sdk-for-go/sdk/azcore require ( github.com/Azure/azure-sdk-for-go/sdk/internal v0.5.2 + github.com/stretchr/testify v1.7.0 // indirect golang.org/x/net v0.0.0-20210610132358-84b48f89b13b ) diff --git a/sdk/azcore/go.sum b/sdk/azcore/go.sum index 62d184faa625..3d9a653b9fb7 100644 --- a/sdk/azcore/go.sum +++ b/sdk/azcore/go.sum @@ -1,11 +1,14 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.5.2 h1:E2xwjsWU81O/XuSaxAGa8Jmqz4Vm4NmrpMSO9/XevDg= github.com/Azure/azure-sdk-for-go/sdk/internal v0.5.2/go.mod h1:Hl9Vte0DDolj9zqzmfnmY9/zfZbiT5KnvXqVwAvnR8Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -19,4 +22,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From ea86e53529aee951c23abd574f29fb53dff7b197 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Fri, 6 Aug 2021 12:26:32 -0400 Subject: [PATCH 08/13] fixing one test --- sdk/azcore/etag_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/azcore/etag_test.go b/sdk/azcore/etag_test.go index c71880dc4167..be8cec923b0c 100644 --- a/sdk/azcore/etag_test.go +++ b/sdk/azcore/etag_test.go @@ -92,7 +92,8 @@ func TestEtagAny(t *testing.T) { require.Falsef(t, StrongEquals(quotedStart, weakStar), "Expected etags to be equal") require.Falsef(t, StrongEquals(star, quotedStart), "Expected etags to be equal") - require.Falsef(t, StrongEquals(ETagAny(), star), "Expected etags to be equal") + + require.Truef(t, StrongEquals(ETagAny(), star), "Expected etags to be equal") } func TestETagWeakComparison(t *testing.T) { From 72f49ccc2034f66baef3bbcedc0c29489c4a43b6 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Fri, 6 Aug 2021 12:59:13 -0400 Subject: [PATCH 09/13] adding EOL --- sdk/azcore/core.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/azcore/core.go b/sdk/azcore/core.go index 1219c5f419c8..ff915e59eae3 100644 --- a/sdk/azcore/core.go +++ b/sdk/azcore/core.go @@ -202,4 +202,4 @@ func IsNullValue(v interface{}) bool { } // no sentinel object for this *t return false -} \ No newline at end of file +} From 76d5720eac8673c5a012f666cc0a47a9b1bbdda3 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Fri, 6 Aug 2021 13:23:03 -0400 Subject: [PATCH 10/13] adding note about the difference between nil and empty etags --- sdk/azcore/etag.go | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/azcore/etag.go b/sdk/azcore/etag.go index 92b3afc22b57..f3865ba43902 100644 --- a/sdk/azcore/etag.go +++ b/sdk/azcore/etag.go @@ -11,6 +11,7 @@ import ( // ETag is a property used for optimistic concurrency during updates // ETag is a validator based on https://tools.ietf.org/html/rfc7232#section-2.3.2 +// An ETag can be empty ("") or nil. A nil etag represents the absence of an ETag, while an empty ETag is a valid ETag (e.g. https://www.rfc-editor.org/rfc/rfc7232.html#section-2.3) type ETag *string // StrongEquals does a strong comparison of two ETags. StrongEquals returns true when both From cd5fe796693af88d0e223382c81df6f1fa049571 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Fri, 6 Aug 2021 17:30:42 -0400 Subject: [PATCH 11/13] more feedback --- sdk/azcore/etag.go | 49 +++++++------------ sdk/azcore/etag_test.go | 104 ++++++++++++++++++++-------------------- 2 files changed, 69 insertions(+), 84 deletions(-) diff --git a/sdk/azcore/etag.go b/sdk/azcore/etag.go index f3865ba43902..ad9306fe7a59 100644 --- a/sdk/azcore/etag.go +++ b/sdk/azcore/etag.go @@ -11,52 +11,37 @@ import ( // ETag is a property used for optimistic concurrency during updates // ETag is a validator based on https://tools.ietf.org/html/rfc7232#section-2.3.2 -// An ETag can be empty ("") or nil. A nil etag represents the absence of an ETag, while an empty ETag is a valid ETag (e.g. https://www.rfc-editor.org/rfc/rfc7232.html#section-2.3) -type ETag *string +// An ETag can be empty (""). +type ETag string -// StrongEquals does a strong comparison of two ETags. StrongEquals returns true when both +// ETagAny is an ETag that represents everything, the value is "*" +const ETagAny ETag = "*" + +// Equals does a strong comparison of two ETags. Equals returns true when both // ETags are not weak and the values of the underlying strings are equal. If both ETags are "nil" they are considered equal -func StrongEquals(a, b ETag) bool { - if !HasValue(a) || !HasValue(b) { - return a == b - } - return !IsWeak(a) && !IsWeak(b) && *a == *b +func (e ETag) Equals(other ETag) bool { + return !e.IsWeak() && !other.IsWeak() && e == other } // WeakEquals does a weak compariosn of two ETags. Two ETags are equivalent if their opaque-tags match // character-by-character, regardless of either or both being tagged as "weak". If both ETags are "nil" they are considered equal -func WeakEquals(a, b ETag) bool { - if !HasValue(a) || !HasValue(b) { - return a == b - } - - getStart := func(e ETag) int { - if IsWeak(e) { +func (e ETag) WeakEquals(other ETag) bool { + getStart := func(e1 ETag) int { + if e1.IsWeak() { return 2 } return 0 } - aStart := getStart(a) - bStart := getStart(b) + aStart := getStart(e) + bStart := getStart(other) - aVal := (*a)[aStart:] - bVal := (*b)[bStart:] + aVal := e[aStart:] + bVal := other[bStart:] return aVal == bVal } -// HasValue returns whether an ETag is present -func HasValue(e ETag) bool { - return e != nil -} - // IsWeak specifies whether the ETag is strong or weak. -func IsWeak(e ETag) bool { - return HasValue(e) && len(*e) >= 4 && strings.HasPrefix(*e, "W/\"") && strings.HasSuffix(*e, "\"") -} - -// ETagAny returns a new ETag that represents everything, the value is "*" -func ETagAny() ETag { - any := "*" - return ETag(&any) +func (e ETag) IsWeak() bool { + return len(e) >= 4 && strings.HasPrefix(string(e), "W/\"") && strings.HasSuffix(string(e), "\"") } diff --git a/sdk/azcore/etag_test.go b/sdk/azcore/etag_test.go index be8cec923b0c..7cbd03fe6edd 100644 --- a/sdk/azcore/etag_test.go +++ b/sdk/azcore/etag_test.go @@ -12,41 +12,41 @@ import ( ) func createETag(s string) ETag { - return ETag(&s) + return ETag(s) } func TestETagEquals(t *testing.T) { e1 := createETag("tag") - require.Equal(t, *e1, "tag") + require.Equal(t, string(e1), "tag") e2 := createETag("\"tag\"") - require.Equal(t, *e2, "\"tag\"") + require.Equal(t, string(e2), "\"tag\"") e3 := createETag("W/\"weakETag\"") - require.Equal(t, *e3, "W/\"weakETag\"") - require.Truef(t, IsWeak(e3), "ETag is ecpected to be weak") + require.Equal(t, string(e3), "W/\"weakETag\"") + require.Truef(t, e3.IsWeak(), "ETag is expected to be weak") strongETag := createETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") - require.Equal(t, *strongETag, "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") + require.Equal(t, string(strongETag), "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") - require.Falsef(t, IsWeak(ETagAny()), "ETagAny should not be weak") + require.Falsef(t, ETagAny.IsWeak(), "ETagAny should not be weak") } func TestETagWeak(t *testing.T) { et1 := createETag("tag") - require.Falsef(t, IsWeak(et1), "expected etag to be strong") + require.Falsef(t, et1.IsWeak(), "expected etag to be strong") et2 := createETag("\"tag\"") - require.Falsef(t, IsWeak(et2), "expected etag to be strong") + require.Falsef(t, et2.IsWeak(), "expected etag to be strong") et3 := createETag("W/\"weakETag\"") - require.Truef(t, IsWeak(et3), "expected etag to be weak") + require.Truef(t, et3.IsWeak(), "expected etag to be weak") et4 := createETag("W/\"\"") - require.Truef(t, IsWeak(et4), "expected etag to be weak") + require.Truef(t, et4.IsWeak(), "expected etag to be weak") - et5 := ETagAny() - require.Falsef(t, IsWeak(et5), "expected etag to be strong") + et5 := ETagAny + require.Falsef(t, et5.IsWeak(), "expected etag to be strong") } func TestETagEquality(t *testing.T) { @@ -58,42 +58,42 @@ func TestETagEquality(t *testing.T) { strongTagValidChars := createETag("\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") weakTagValidChars := createETag("W/\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") - require.Falsef(t, StrongEquals(weakTag, weakTag), "Expected etags to not be equal") - require.Falsef(t, StrongEquals(weakTag1, weakTag1), "Expected etags to not be equal") - require.Falsef(t, StrongEquals(weakTag2, weakTag2), "Expected etags to not be equal") - require.Falsef(t, StrongEquals(weakTagValidChars, weakTagValidChars), "Expected etags to not be equal") + require.Falsef(t, weakTag.Equals(weakTag), "Expected etags to not be equal") + require.Falsef(t, weakTag1.Equals( weakTag1), "Expected etags to not be equal") + require.Falsef(t, weakTag2.Equals(weakTag2), "Expected etags to not be equal") + require.Falsef(t, weakTagValidChars.Equals(weakTagValidChars), "Expected etags to not be equal") - require.Truef(t, StrongEquals(strongTag1, strongTag1), "Expected etags to be equal") - require.Truef(t, StrongEquals(strongTag2, strongTag2), "Expected etags to be equal") - require.Truef(t, StrongEquals(strongTagValidChars, strongTagValidChars), "Expected etags to be equal") + require.Truef(t, strongTag1.Equals(strongTag1), "Expected etags to be equal") + require.Truef(t, strongTag2.Equals(strongTag2), "Expected etags to be equal") + require.Truef(t, strongTagValidChars.Equals(strongTagValidChars), "Expected etags to be equal") - require.Falsef(t, StrongEquals(weakTag, weakTag1), "Expected etags to not be equal") - require.Falsef(t, StrongEquals(weakTagValidChars, strongTagValidChars), "Expected etags to not be equal") - require.Falsef(t, StrongEquals(weakTag1, weakTag2), "Expected etags to not be equal") - require.Falsef(t, StrongEquals(weakTag1, strongTag1), "Expected etags to not be equal") - require.Falsef(t, StrongEquals(weakTag2, strongTag2), "Expected etags to not be equal") + require.Falsef(t, weakTag1.Equals(weakTag), "Expected etags to not be equal") + require.Falsef(t, strongTagValidChars.Equals(weakTagValidChars), "Expected etags to not be equal") + require.Falsef(t, weakTag2.Equals(weakTag1), "Expected etags to not be equal") + require.Falsef(t, strongTag1.Equals(weakTag1), "Expected etags to not be equal") + require.Falsef(t, strongTag2.Equals(weakTag2), "Expected etags to not be equal") } func TestEtagAny(t *testing.T) { - anyETag := ETagAny() + anyETag := ETagAny star := createETag("*") weakStar := createETag("W\"*\"") - quotedStart := createETag("\"*\"") + quotedStar := createETag("\"*\"") - require.Truef(t, StrongEquals(anyETag, anyETag), "Expected etags to be equal") - require.Truef(t, StrongEquals(anyETag, ETagAny()), "Expected etags to be equal") + require.Truef(t, anyETag.Equals(anyETag), "Expected etags to be equal") + require.Truef(t, ETagAny.Equals(anyETag), "Expected etags to be equal") - require.Truef(t, StrongEquals(star, star), "Expected etags to be equal") - require.Truef(t, StrongEquals(star, ETagAny()), "Expected etags to be equal") - require.Truef(t, StrongEquals(star, anyETag), "Expected etags to be equal") + require.Truef(t, star.Equals(star), "Expected etags to be equal") + require.Truef(t, ETagAny.Equals(star), "Expected etags to be equal") + require.Truef(t, anyETag.Equals(star), "Expected etags to be equal") - require.Falsef(t, StrongEquals(weakStar, star), "Expected etags to be equal") - require.Falsef(t, StrongEquals(weakStar, ETagAny()), "Expected etags to be equal") - require.Falsef(t, StrongEquals(quotedStart, weakStar), "Expected etags to be equal") + require.Falsef(t, star.Equals(weakStar), "Expected etags to be equal") + require.Falsef(t, ETagAny.Equals(weakStar), "Expected etags to be equal") + require.Falsef(t, weakStar.Equals(quotedStar), "Expected etags to be equal") - require.Falsef(t, StrongEquals(star, quotedStart), "Expected etags to be equal") + require.Falsef(t, quotedStar.Equals(star), "Expected etags to be equal") - require.Truef(t, StrongEquals(ETagAny(), star), "Expected etags to be equal") + require.Truef(t, star.Equals(ETagAny), "Expected etags to be equal") } func TestETagWeakComparison(t *testing.T) { @@ -112,23 +112,23 @@ func TestETagWeakComparison(t *testing.T) { // "two" strongTagtwo := createETag("\"two\"") - require.Truef(t, WeakEquals(weakTag, weakTag), "expected etags to be equal") - require.Truef(t, WeakEquals(weakTag1, weakTag1), "expected etags to be equal") - require.Truef(t, WeakEquals(weakTagTwo, weakTagTwo), "expected etags to be equal") - require.Truef(t, WeakEquals(weakTagtwo, weakTagtwo), "expected etags to be equal") - require.Truef(t, WeakEquals(strongTag1, strongTag1), "expected etags to be equal") - require.Truef(t, WeakEquals(strongTagTwo, strongTagTwo), "expected etags to be equal") - require.Truef(t, WeakEquals(strongTagtwo, strongTagtwo), "expected etags to be equal") + require.Truef(t, weakTag.WeakEquals(weakTag), "expected etags to be equal") + require.Truef(t, weakTag1.WeakEquals(weakTag1), "expected etags to be equal") + require.Truef(t, weakTagTwo.WeakEquals(weakTagTwo), "expected etags to be equal") + require.Truef(t, weakTagtwo.WeakEquals(weakTagtwo), "expected etags to be equal") + require.Truef(t, strongTag1.WeakEquals(strongTag1), "expected etags to be equal") + require.Truef(t, strongTagTwo.WeakEquals(strongTagTwo), "expected etags to be equal") + require.Truef(t, strongTagtwo.WeakEquals(strongTagtwo), "expected etags to be equal") - require.Falsef(t, WeakEquals(weakTag, weakTag1), "Expected etags to not be equal") - require.Falsef(t, WeakEquals(weakTag1, weakTagTwo), "Expected etags to not be equal") + require.Falsef(t, weakTag1.WeakEquals(weakTag), "Expected etags to not be equal") + require.Falsef(t, weakTagTwo.WeakEquals(weakTag1), "Expected etags to not be equal") - require.Truef(t, WeakEquals(weakTag1, strongTag1), "expected etags to be equal") - require.Truef(t, WeakEquals(weakTagTwo, strongTagTwo), "expected etags to be equal") + require.Truef(t, strongTag1.WeakEquals(weakTag1), "expected etags to be equal") + require.Truef(t, strongTagTwo.WeakEquals(weakTagTwo), "expected etags to be equal") - require.Falsef(t, WeakEquals(strongTagTwo, weakTag1), "Expected etags to not be equal") - require.Falsef(t, WeakEquals(strongTagTwo, weakTagtwo), "Expected etags to not be equal") + require.Falsef(t, weakTag1.WeakEquals(strongTagTwo), "Expected etags to not be equal") + require.Falsef(t, weakTagtwo.WeakEquals(strongTagTwo), "Expected etags to not be equal") - require.Falsef(t, WeakEquals(strongTagTwo, strongTagtwo), "Expected etags to not be equal") - require.Falsef(t, WeakEquals(weakTagTwo, weakTagtwo), "Expected etags to not be equal") + require.Falsef(t, strongTagtwo.WeakEquals(strongTagTwo), "Expected etags to not be equal") + require.Falsef(t, weakTagtwo.WeakEquals(weakTagTwo), "Expected etags to not be equal") } From c6a099d1aa83778bdc677a707bc4ca9d21f6cfa6 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Mon, 9 Aug 2021 10:09:14 -0400 Subject: [PATCH 12/13] fix spelling, remove comment about nil --- sdk/azcore/etag.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/azcore/etag.go b/sdk/azcore/etag.go index ad9306fe7a59..983af5b6524b 100644 --- a/sdk/azcore/etag.go +++ b/sdk/azcore/etag.go @@ -18,13 +18,13 @@ type ETag string const ETagAny ETag = "*" // Equals does a strong comparison of two ETags. Equals returns true when both -// ETags are not weak and the values of the underlying strings are equal. If both ETags are "nil" they are considered equal +// ETags are not weak and the values of the underlying strings are equal. func (e ETag) Equals(other ETag) bool { return !e.IsWeak() && !other.IsWeak() && e == other } -// WeakEquals does a weak compariosn of two ETags. Two ETags are equivalent if their opaque-tags match -// character-by-character, regardless of either or both being tagged as "weak". If both ETags are "nil" they are considered equal +// WeakEquals does a weak comparison of two ETags. Two ETags are equivalent if their opaque-tags match +// character-by-character, regardless of either or both being tagged as "weak". func (e ETag) WeakEquals(other ETag) bool { getStart := func(e1 ETag) int { if e1.IsWeak() { From ae8d2972891a889fe127754d165c2de612ebd935 Mon Sep 17 00:00:00 2001 From: seankane-msft Date: Mon, 9 Aug 2021 10:37:11 -0400 Subject: [PATCH 13/13] format check --- sdk/azcore/etag_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/azcore/etag_test.go b/sdk/azcore/etag_test.go index 7cbd03fe6edd..5541fe05a20a 100644 --- a/sdk/azcore/etag_test.go +++ b/sdk/azcore/etag_test.go @@ -59,7 +59,7 @@ func TestETagEquality(t *testing.T) { weakTagValidChars := createETag("W/\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"") require.Falsef(t, weakTag.Equals(weakTag), "Expected etags to not be equal") - require.Falsef(t, weakTag1.Equals( weakTag1), "Expected etags to not be equal") + require.Falsef(t, weakTag1.Equals(weakTag1), "Expected etags to not be equal") require.Falsef(t, weakTag2.Equals(weakTag2), "Expected etags to not be equal") require.Falsef(t, weakTagValidChars.Equals(weakTagValidChars), "Expected etags to not be equal")