Repository: goadesign/goa
Pull request #2366 (2019-11-05 22:38:14)

Fix short-circuiting in hasTag and iterate through all bases

raphael: Thank you! Can you please back-port to v2 as well?

Patch:
diff --git a/expr/method.go b/expr/method.go
index ada71ddd..fc97affe 100644
--- a/expr/method.go
+++ b/expr/method.go
@@ -228,7 +228,9 @@ func hasTag(p *AttributeExpr, tag string) bool {
 		if !ok {
 			continue
 		}
-		return hasTag(ut.Attribute(), tag)
+		if hasTag(ut.Attribute(), tag) {
+			return true
+		}
 	}
 	if ut, ok := p.Type.(UserType); ok {
 		return hasTag(ut.Attribute(), tag)
@@ -248,7 +250,9 @@ func hasTagPrefix(p *AttributeExpr, prefix string) bool {
 		if !ok {
 			continue
 		}
-		return hasTagPrefix(ut.Attribute(), prefix)
+		if hasTagPrefix(ut.Attribute(), prefix) {
+			return true
+		}
 	}
 	if ut, ok := p.Type.(UserType); ok {
 		return hasTagPrefix(ut.Attribute(), prefix)


Test patch:
diff --git a/expr/method_test.go b/expr/method_test.go
index 0d97b847..f17da484 100644
--- a/expr/method_test.go
+++ b/expr/method_test.go
@@ -14,6 +14,7 @@ func TestMethodExprValidate(t *testing.T) {
 		DSL   func()
 		Error string
 	}{
+		{"valid-security-schemes-extend", testdata.ValidSecuritySchemesExtendDSL, ""},
 		{"invalid-security-schemes", testdata.InvalidSecuritySchemesDSL,
 			`service "InvalidSecuritySchemesService" method "SecureMethod": payload of method "SecureMethod" of service "InvalidSecuritySchemesService" does not define a username attribute, use Username to define one
 service "InvalidSecuritySchemesService" method "SecureMethod": payload of method "SecureMethod" of service "InvalidSecuritySchemesService" does not define a password attribute, use Password to define one
@@ -34,9 +35,13 @@ service "AnotherInvalidSecuritySchemesService" method "Method": payload of metho
 	}
 	for _, tc := range cases {
 		t.Run(tc.Name, func(t *testing.T) {
-			err := expr.RunInvalidDSL(t, tc.DSL)
-			if tc.Error != err.Error() {
-				t.Errorf("invalid error:\ngot:\n%s\n\ngot vs expected:\n%s", err.Error(), expr.Diff(t, err.Error(), tc.Error))
+			if tc.Error == "" {
+				expr.RunDSL(t, tc.DSL)
+			} else {
+				err := expr.RunInvalidDSL(t, tc.DSL)
+				if tc.Error != err.Error() {
+					t.Errorf("invalid error:\ngot:\n%s\n\ngot vs expected:\n%s", err.Error(), expr.Diff(t, err.Error(), tc.Error))
+				}
 			}
 		})
 	}
diff --git a/expr/testdata/method_validate_dsls.go b/expr/testdata/method_validate_dsls.go
index 96f34d75..ed43ad8c 100644
--- a/expr/testdata/method_validate_dsls.go
+++ b/expr/testdata/method_validate_dsls.go
@@ -18,6 +18,25 @@ var OAuth2 = OAuth2Security("authCode", func() {
 	Scope("api:read", "Read access")
 })
 
+var ValidSecuritySchemesExtendDSL = func() {
+	var CommonAttr = Type("Common", func() {
+		Attribute("version", String)
+	})
+	var SecurityAttr = Type("Security", func() {
+		Username("user", String)
+		Password("pass", String)
+	})
+	Service("ValidSecuritySchemesExtendService", func() {
+		Method("SecureMethod", func() {
+			Security(BasicAuth)
+			Payload(func() {
+				Extend(CommonAttr)
+				Extend(SecurityAttr)
+			})
+		})
+	})
+}
+
 var InvalidSecuritySchemesDSL = func() {
 	Service("InvalidSecuritySchemesService", func() {
 		Security(OAuth2, APIKeyAuth, func() {