-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#3 added resource pattern filter to match resource patterns
- Loading branch information
Krishnakant C
authored and
Krishnakant C
committed
Sep 10, 2024
1 parent
b00fe84
commit d915481
Showing
5 changed files
with
300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package resource | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
// ResourcePattern represents a pattern used by ACLs to match zero or more resources. | ||
type ResourcePattern struct { | ||
resourceType ResourceType | ||
name string | ||
patternType PatternType | ||
} | ||
|
||
const ( | ||
// WILDCARD_RESOURCE is a special literal resource name that corresponds to 'all resources of a certain type'. | ||
WILDCARD_RESOURCE = "*" | ||
) | ||
|
||
// NewResourcePattern creates a new ResourcePattern using the supplied parameters. | ||
func NewResourcePattern(resourceType ResourceType, name string, patternType PatternType) (*ResourcePattern, error) { | ||
if resourceType == UNRECOGNIZED { | ||
return nil, errors.New("resourceType cannot be UNRECOGNIZED") | ||
} | ||
if patternType == UNKNOWN { | ||
return nil, errors.New("patternType cannot be UNKNOWN") | ||
} | ||
return &ResourcePattern{ | ||
resourceType: resourceType, | ||
name: name, | ||
patternType: patternType, | ||
}, nil | ||
} | ||
|
||
// ResourceType returns the specific resource type this pattern matches. | ||
func (rp *ResourcePattern) ResourceType() ResourceType { | ||
return rp.resourceType | ||
} | ||
|
||
// Name returns the resource name. | ||
func (rp *ResourcePattern) Name() string { | ||
return rp.name | ||
} | ||
|
||
// PatternType returns the resource pattern type. | ||
func (rp *ResourcePattern) PatternType() PatternType { | ||
return rp.patternType | ||
} | ||
|
||
// ToFilter returns a filter which matches only this pattern. | ||
func (rp *ResourcePattern) ToFilter() (*ResourcePatternFilter, error) { | ||
return NewResourcePatternFilter(rp.resourceType, rp.name, rp.patternType) | ||
} | ||
|
||
// IsUnknown returns true if this ResourcePattern has any UNKNOWN components. | ||
func (rp *ResourcePattern) IsUnknown() bool { | ||
return rp.resourceType == UNRECOGNIZED || rp.patternType == UNKNOWN | ||
} | ||
|
||
// String returns a string representation of the ResourcePattern. | ||
func (p *ResourcePattern) String() string { | ||
return fmt.Sprintf("ResourcePattern{resourceType=%s, name=%q, patternType=%s}", p.resourceType.String(), p.name, p.patternType.String()) | ||
} | ||
|
||
// Equals checks if two ResourcePatterns are equal. | ||
func (rp *ResourcePattern) Equals(other *ResourcePattern) bool { | ||
return other != nil && rp.resourceType == other.resourceType && rp.name == other.name && rp.patternType == other.patternType | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package resource | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
// ResourcePatternFilter represents a filter that can match ResourcePattern. | ||
type ResourcePatternFilter struct { | ||
resourceType ResourceType | ||
name string | ||
patternType PatternType | ||
} | ||
|
||
// NewResourcePatternFilter creates a new ResourcePatternFilter. | ||
func NewResourcePatternFilter(resourceType ResourceType, name string, patternType PatternType) (*ResourcePatternFilter, error) { | ||
if resourceType == UNRECOGNIZED { | ||
return nil, errors.New("resourceType cannot be UNRECOGNIZED") | ||
} | ||
if patternType == UNKNOWN { | ||
return nil, errors.New("patternType cannot be UNKNOWN") | ||
} | ||
return &ResourcePatternFilter{ | ||
resourceType: resourceType, | ||
name: name, | ||
patternType: patternType, | ||
}, nil | ||
} | ||
|
||
// AnyResourcePatternFilter creates a filter that matches any resource pattern. | ||
func AnyResourcePatternFilter() *ResourcePatternFilter { | ||
filter, _ := NewResourcePatternFilter(ALL_RESOURCES, "", ANY) | ||
return filter | ||
} | ||
|
||
// IsUnknown checks if the filter has any UNKNOWN components. | ||
func (f *ResourcePatternFilter) IsUnknown() bool { | ||
return f.resourceType == UNRECOGNIZED || f.patternType == UNKNOWN | ||
} | ||
|
||
// ResourceType returns the specific resource type this pattern matches. | ||
func (f *ResourcePatternFilter) ResourceType() ResourceType { | ||
return f.resourceType | ||
} | ||
|
||
// Name returns the resource name. | ||
func (f *ResourcePatternFilter) Name() string { | ||
return f.name | ||
} | ||
|
||
// PatternType returns the resource pattern type. | ||
func (f *ResourcePatternFilter) PatternType() PatternType { | ||
return f.patternType | ||
} | ||
|
||
// Matches checks if the filter matches the given ResourcePattern. | ||
func (f *ResourcePatternFilter) Matches(pattern *ResourcePattern) bool { | ||
if pattern == nil { | ||
return false | ||
} | ||
|
||
if f.resourceType != ALL_RESOURCES && f.resourceType != pattern.resourceType { | ||
return false | ||
} | ||
|
||
if f.patternType != ANY && f.patternType != MATCH && f.patternType != pattern.patternType { | ||
return false | ||
} | ||
|
||
if f.name == "" { | ||
return true | ||
} | ||
|
||
return f.nameMatches(pattern) | ||
} | ||
|
||
// nameMatches checks if the name matches based on the pattern type. | ||
func (f *ResourcePatternFilter) nameMatches(pattern *ResourcePattern) bool { | ||
switch { | ||
case f.patternType == ANY: | ||
return true | ||
case f.patternType == pattern.patternType: | ||
return f.name == pattern.name || f.name == WILDCARD_RESOURCE | ||
case f.patternType == PREFIXED: | ||
// Match if the pattern name starts with the filter's name | ||
return strings.HasPrefix(pattern.name, f.name) | ||
case pattern.patternType == LITERAL: | ||
return f.name == pattern.name || pattern.name == WILDCARD_RESOURCE | ||
default: | ||
return false // Return false for unsupported pattern types | ||
} | ||
} | ||
|
||
// MatchesAtMostOne checks if the filter could only match one pattern. | ||
func (f *ResourcePatternFilter) MatchesAtMostOne() bool { | ||
return f.findIndefiniteField() == "" | ||
} | ||
|
||
// findIndefiniteField returns a string describing any indefinite field, or an empty string if none. | ||
func (f *ResourcePatternFilter) findIndefiniteField() string { | ||
switch { | ||
case f.resourceType == ALL_RESOURCES: | ||
return "Resource type is ALL_RESOURCES." | ||
case f.resourceType == UNRECOGNIZED: | ||
return "Resource type is UNRECOGNIZED." | ||
case f.name == "": | ||
return "Resource name is empty." | ||
case f.patternType == MATCH: | ||
return "Resource pattern type is MATCH." | ||
case f.patternType == UNKNOWN: | ||
return "Resource pattern type is UNKNOWN." | ||
default: | ||
return "" | ||
} | ||
} | ||
|
||
// String returns a string representation of the ResourcePatternFilter. | ||
func (f *ResourcePatternFilter) String() string { | ||
return fmt.Sprintf("ResourcePatternFilter{resourceType=%s, name=%q, patternType=%s}", f.resourceType.String(), f.name, f.patternType.String()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package resource | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestNewResourcePatternFilter(t *testing.T) { | ||
_, err := NewResourcePatternFilter(UNRECOGNIZED, "topic1", LITERAL) | ||
if err == nil { | ||
t.Errorf("NewResourcePatternFilter should return an error for UNRECOGNIZED resourceType") | ||
} | ||
|
||
_, err = NewResourcePatternFilter(TOPIC, "topic1", UNKNOWN) | ||
if err == nil { | ||
t.Errorf("NewResourcePatternFilter should return an error for UNKNOWN patternType") | ||
} | ||
|
||
filter, err := NewResourcePatternFilter(TOPIC, "topic1", LITERAL) | ||
if err != nil { | ||
t.Errorf("NewResourcePatternFilter returned an unexpected error: %v", err) | ||
} | ||
if filter == nil { | ||
t.Errorf("NewResourcePatternFilter returned a nil filter") | ||
} | ||
} | ||
|
||
func TestAnyResourcePatternFilter(t *testing.T) { | ||
filter := AnyResourcePatternFilter() | ||
if filter.resourceType != ALL_RESOURCES { | ||
t.Errorf("AnyResourcePatternFilter should return a filter with resourceType ALL_RESOURCES") | ||
} | ||
if filter.name != "" { | ||
t.Errorf("AnyResourcePatternFilter should return a filter with empty name") | ||
} | ||
if filter.patternType != ANY { | ||
t.Errorf("AnyResourcePatternFilter should return a filter with patternType ANY") | ||
} | ||
} | ||
|
||
func TestResourcePatternFilter_Matches(t *testing.T) { | ||
filter, _ := NewResourcePatternFilter(TOPIC, "payments.received", LITERAL) | ||
pattern, _ := NewResourcePattern(TOPIC, "payments.received", LITERAL) | ||
if !filter.Matches(pattern) { | ||
t.Errorf("ResourcePatternFilter should match the exact pattern") | ||
} | ||
|
||
filter, _ = NewResourcePatternFilter(TOPIC, "payments.", PREFIXED) | ||
pattern, _ = NewResourcePattern(TOPIC, "payments.received", LITERAL) | ||
if !filter.Matches(pattern) { | ||
t.Errorf("Expected filter to match the pattern: filter=%s, pattern=%s", filter, pattern) | ||
} | ||
|
||
filter, _ = NewResourcePatternFilter(TOPIC, "*", LITERAL) | ||
pattern, _ = NewResourcePattern(TOPIC, "payments.received", LITERAL) | ||
if !filter.Matches(pattern) { | ||
t.Errorf("ResourcePatternFilter should match the wildcard pattern") | ||
} | ||
|
||
filter, _ = NewResourcePatternFilter(TOPIC, "payments.received", LITERAL) | ||
pattern, _ = NewResourcePattern(GROUP, "payments.received", LITERAL) | ||
if filter.Matches(pattern) { | ||
t.Errorf("ResourcePatternFilter should not match a pattern with different resourceType") | ||
} | ||
|
||
filter, _ = NewResourcePatternFilter(TOPIC, "payments.received", LITERAL) | ||
pattern, _ = NewResourcePattern(TOPIC, "payments.received", PREFIXED) | ||
if filter.Matches(pattern) { | ||
t.Errorf("ResourcePatternFilter should not match a pattern with different patternType") | ||
} | ||
} | ||
|
||
func TestResourcePatternFilter_MatchesAtMostOne(t *testing.T) { | ||
filter, _ := NewResourcePatternFilter(TOPIC, "payments.received", LITERAL) | ||
if !filter.MatchesAtMostOne() { | ||
t.Errorf("ResourcePatternFilter should match at most one pattern") | ||
} | ||
|
||
filter, _ = NewResourcePatternFilter(ALL_RESOURCES, "payments.received", LITERAL) | ||
if filter.MatchesAtMostOne() { | ||
t.Errorf("ResourcePatternFilter with resourceType ALL_RESOURCES should not match at most one pattern") | ||
} | ||
|
||
filter, _ = NewResourcePatternFilter(TOPIC, "", LITERAL) | ||
if filter.MatchesAtMostOne() { | ||
t.Errorf("ResourcePatternFilter with empty name should not match at most one pattern") | ||
} | ||
|
||
filter, _ = NewResourcePatternFilter(TOPIC, "payments.received", MATCH) | ||
if filter.MatchesAtMostOne() { | ||
t.Errorf("ResourcePatternFilter with patternType MATCH should not match at most one pattern") | ||
} | ||
} | ||
|
||
func TestResourcePatternFilter_String(t *testing.T) { | ||
filter, _ := NewResourcePatternFilter(TOPIC, "payments.received", LITERAL) | ||
expected := `ResourcePatternFilter{resourceType=TOPIC, name="payments.received", patternType=LITERAL}` | ||
if filter.String() != expected { | ||
t.Errorf("ResourcePatternFilter.String() returned unexpected value: %s", filter.String()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters