Skip to content

Commit

Permalink
#3 added reosurce type of a resource which an ACL can be applied to
Browse files Browse the repository at this point in the history
  • Loading branch information
Krishnakant C authored and Krishnakant C committed Sep 10, 2024
1 parent b3b7f6f commit b00fe84
Show file tree
Hide file tree
Showing 2 changed files with 238 additions and 0 deletions.
121 changes: 121 additions & 0 deletions pkg/resource/resource_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright 2024 Atomstate Technologies Private Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package resource

import (
"errors"
"strings"
)

// ResourceType represents a type of resource which an ACL can be applied to.
type ResourceType byte

const (
// UNRECOGNIZED represents any ResourceType which this client cannot understand.
UNRECOGNIZED ResourceType = iota

// ALL_RESOURCES matches any ResourceType.
ALL_RESOURCES

// TOPIC represents a Kafka topic.
TOPIC

// GROUP represents a consumer group.
GROUP

// CLUSTER represents the cluster as a whole.
CLUSTER

// TRANSACTIONAL_ID represents a transactional ID.
TRANSACTIONAL_ID

// DELEGATION_TOKEN represents a token ID.
DELEGATION_TOKEN

// USER represents a user principal.
USER

resourceTypeCount // Keep this at the end for the number of resource types
)

// resourceTypeNames maps ResourceType values to their string representations.
var resourceTypeNames = [resourceTypeCount]string{
"UNRECOGNIZED",
"ALL_RESOURCES",
"TOPIC",
"GROUP",
"CLUSTER",
"TRANSACTIONAL_ID",
"DELEGATION_TOKEN",
"USER",
}

// FromString parses the given string as an ACL resource type.
//
// Example usage:
//
// resType, err := FromString("topic")
// if err != nil {
// fmt.Println(err)
// } else {
// fmt.Printf("Parsed ResourceType: %d\n", resType)
// }
//
// This will output:
//
// Parsed ResourceType: 2
func FromString(str string) (ResourceType, error) {
if str == "" {
return UNRECOGNIZED, errors.New("input string is empty")
}

// Normalize the input string to upper case for comparison
str = strings.ToUpper(str)

for i := range resourceTypeNames {
if resourceTypeNames[i] == str {
return ResourceType(i), nil
}
}
return UNRECOGNIZED, errors.New("unknown resource type")
}

// FromCode returns the ResourceType with the provided code or UNRECOGNIZED if one cannot be found.
//
// Example usage:
//
// code := byte(3)
// resTypeFromCode := FromCode(code)
// fmt.Printf("ResourceType from code %d: %d\n", code, resTypeFromCode)
//
// This will output:
//
// ResourceType from code 3: 3
func FromCode(code byte) ResourceType {
if code < byte(resourceTypeCount) {
return ResourceType(code)
}
return UNRECOGNIZED
}

// Code returns the code of this resource type.
func (r ResourceType) Code() byte {
return byte(r)
}

// IsUnrecognized returns whether this resource type is UNRECOGNIZED.
func (r ResourceType) IsUnrecognized() bool {
return r == UNRECOGNIZED
}
117 changes: 117 additions & 0 deletions pkg/resource/resource_type_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2024 Atomstate Technologies Private Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package resource

import "testing"

// Unit tests
func TestFromString(t *testing.T) {
tests := []struct {
input string
expected ResourceType
hasError bool
}{
{"UNRECOGNIZED", UNRECOGNIZED, false},
{"ALL_RESOURCES", ALL_RESOURCES, false},
{"TOPIC", TOPIC, false},
{"GROUP", GROUP, false},
{"CLUSTER", CLUSTER, false},
{"TRANSACTIONAL_ID", TRANSACTIONAL_ID, false},
{"DELEGATION_TOKEN", DELEGATION_TOKEN, false},
{"USER", USER, false},
{"", UNRECOGNIZED, true}, // empty string, expect error
{"INVALID_TYPE", UNRECOGNIZED, true}, // invalid type, expect error
}

for _, test := range tests {
result, err := FromString(test.input)
if (err != nil) != test.hasError {
t.Errorf("FromString(%q) error = %v, wantError %v", test.input, err, test.hasError)
}
if result != test.expected {
t.Errorf("FromString(%q) = %v, want %v", test.input, result, test.expected)
}
}
}

func TestFromCode(t *testing.T) {
tests := []struct {
code byte
expected ResourceType
}{
{0, UNRECOGNIZED},
{1, ALL_RESOURCES},
{2, TOPIC},
{3, GROUP},
{4, CLUSTER},
{5, TRANSACTIONAL_ID},
{6, DELEGATION_TOKEN},
{7, USER},
{8, UNRECOGNIZED}, // out of bounds
}

for _, test := range tests {
result := FromCode(test.code)
if result != test.expected {
t.Errorf("FromCode(%d) = %v, want %v", test.code, result, test.expected)
}
}
}

func TestRTCode(t *testing.T) {
tests := []struct {
resourceType ResourceType
expectedCode byte
}{
{UNRECOGNIZED, 0},
{ALL_RESOURCES, 1},
{TOPIC, 2},
{GROUP, 3},
{CLUSTER, 4},
{TRANSACTIONAL_ID, 5},
{DELEGATION_TOKEN, 6},
{USER, 7},
}

for _, test := range tests {
result := test.resourceType.Code()
if result != test.expectedCode {
t.Errorf("Code() for %v = %d, want %d", test.resourceType, result, test.expectedCode)
}
}
}

func TestIsUnrecognized(t *testing.T) {
tests := []struct {
resourceType ResourceType
expected bool
}{
{UNRECOGNIZED, true},
{ALL_RESOURCES, false},
{TOPIC, false},
{GROUP, false},
{CLUSTER, false},
{TRANSACTIONAL_ID, false},
{DELEGATION_TOKEN, false},
{USER, false},
}

for _, test := range tests {
result := test.resourceType.IsUnrecognized()
if result != test.expected {
t.Errorf("IsUnrecognized() for %v = %v, want %v", test.resourceType, result, test.expected)
}
}
}

0 comments on commit b00fe84

Please sign in to comment.