repo_description: Apache Casbin: an authorization library that supports access control models like ACL, RBAC, ABAC.
repo_topics: abac access-control acl apache auth authentication authn authorization authz cas casbin iam oauth oidc permission rbac saml sso
code: // Copyright 2026 The casbin Authors. All Rights Reserved.
  //
  // 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 casbin
  
  import (
  	"bytes"
  	"strings"
  	"testing"
  
  	"github.com/casbin/casbin/v3/log"
  )
  
  func verifyBufferOutput(t *testing.T, logOutput string) {
  	t.Helper()
  	expectedEvents := []string{"[enforce]", "[addPolicy]", "[removePolicy]", "[savePolicy]", "[loadPolicy]"}
  	for _, event := range expectedEvents {
  		if !strings.Contains(logOutput, event) {
  			t.Errorf("Expected log output to contain %s event", event)
  		}
  	}
  }
  
  func verifyCallbackEntries(t *testing.T, entries []*log.LogEntry) {
  	t.Helper()
  	found := map[log.EventType]bool{}
  
  	for _, entry := range entries {
  		found[entry.EventType] = true
  		switch entry.EventType {
  		case log.EventEnforce:
  			if entry.Subject == "" && entry.Object == "" && entry.Action == "" {
  				t.Errorf("Expected enforce entry to have subject, object, and action")
  			}
  		case log.EventAddPolicy, log.EventRemovePolicy:
  			if entry.RuleCount != 1 {
  				t.Errorf("Expected %s entry to have RuleCount=1, got %d", entry.EventType, entry.RuleCount)
  			}
  		case log.EventSavePolicy, log.EventLoadPolicy:
  			if entry.RuleCount == 0 {
  				t.Errorf("Expected %s entry to have RuleCount>0", entry.EventType)
  			}
  		}
  	}
  
  	requiredEvents := []log.EventType{
  		log.EventEnforce, log.EventAddPolicy, log.EventRemovePolicy,
  		log.EventSavePolicy, log.EventLoadPolicy,
  	}
  	for _, eventType := range requiredEvents {
  		if !found[eventType] {
  			t.Errorf("Expected to find %s in callback entries", eventType)
  		}
  	}
  }
  
  func TestEnforcerWithDefaultLogger(t *testing.T) {
  	// Create enforcer with RBAC model and policy
  	e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
  	if err != nil {
  		t.Fatalf("Failed to create enforcer: %v", err)
  	}
  
  	// Create a buffer to capture log output
  	var buf bytes.Buffer
  	logger := log.NewDefaultLogger()
  	logger.SetOutput(&buf)
  
  	// Set up a callback to track log entries
  	var callbackEntries []*log.LogEntry
  	err = logger.SetLogCallback(func(entry *log.LogEntry) error {
  		// Create a copy of the entry to store
  		entryCopy := *entry
  		callbackEntries = append(callbackEntries, &entryCopy)
  		return nil
  	})
  	if err != nil {
  		t.Fatalf("Failed to set log callback: %v", err)
  	}
  
  	// Set the logger on the enforcer
  	e.SetLogger(logger)
  
  	// Test Enforce events
  	if result, err := e.Enforce("alice", "data1", "read"); err != nil {
  		t.Fatalf("Enforce failed: %v", err)
  	} else if !result {
  		t.Errorf("Expected alice to have read access to data1")
  	}
  
  	if result, err := e.Enforce("bob", "data2", "write"); err != nil {
  		t.Fatalf("Enforce failed: %v", err)
  	} else if !result {
  		t.Errorf("Expected bob to have write access to data2")
  	}
  
  	// Test AddPolicy event
  	if added, err := e.AddPolicy("charlie", "data3", "read"); err != nil {
  		t.Fatalf("AddPolicy failed: %v", err)
  	} else if !added {
  		t.Errorf("Expected policy to be added")
  	}
  
  	// Test RemovePolicy event
  	if removed, err := e.RemovePolicy("charlie", "data3", "read"); err != nil {
  		t.Fatalf("RemovePolicy failed: %v", err)
  	} else if !removed {
  		t.Errorf("Expected policy to be removed")
  	}
  
  	// Test SavePolicy and LoadPolicy events
  	if err := e.SavePolicy(); err != nil {
  		t.Fatalf("SavePolicy failed: %v", err)
  	}
  	if err := e.LoadPolicy(); err != nil {
  		t.Fatalf("LoadPolicy failed: %v", err)
  	}
  
  	// Verify buffer output and callback entries
  	verifyBufferOutput(t, buf.String())
  
  	if len(callbackEntries) == 0 {
  		t.Fatalf("Expected callback to be called, but got no entries")
  	}
  	verifyCallbackEntries(t, callbackEntries)
  }
  
  func TestSetEventTypes(t *testing.T) {
  	// Create enforcer with RBAC model and policy
  	e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
  	if err != nil {
  		t.Fatalf("Failed to create enforcer: %v", err)
  	}
  
  	// Create a buffer to capture log output
  	var buf bytes.Buffer
  	logger := log.NewDefaultLogger()
  	logger.SetOutput(&buf)
  
  	// Set up a callback to track log entries
  	var callbackEntries []*log.LogEntry
  	err = logger.SetLogCallback(func(entry *log.LogEntry) error {
  		// Create a copy of the entry to store
  		entryCopy := *entry
  		callbackEntries = append(callbackEntries, &entryCopy)
  		return nil
  	})
  	if err != nil {
  		t.Fatalf("Failed to set log callback: %v", err)
  	}
  
  	// Configure logger to only log EventEnforce and EventAddPolicy
  	err = logger.SetEventTypes([]log.EventType{log.EventEnforce, log.EventAddPolicy})
  	if err != nil {
  		t.Fatalf("Failed to set event types: %v", err)
  	}
  
  	// Set the logger on the enforcer
  	e.SetLogger(logger)
  
  	// Perform various operations
  	_, err = e.Enforce("alice", "data1", "read")
  	if err != nil {
  		t.Fatalf("Enforce failed: %v", err)
  	}
  
  	_, err = e.AddPolicy("charlie", "data3", "read")
  	if err != nil {
  		t.Fatalf("AddPolicy failed: %v", err)
  	}
  
  	_, err = e.RemovePolicy("charlie", "data3", "read")
  	if err != nil {
  		t.Fatalf("RemovePolicy failed: %v", err)
  	}
  
  	if err := e.LoadPolicy(); err != nil {
  		t.Fatalf("LoadPolicy failed: %v", err)
  	}
  
  	// Verify buffer output only contains EventEnforce and EventAddPolicy
  	verifySelectiveBufferOutput(t, buf.String())
  
  	// Verify callback entries
  	verifySelectiveCallbackEntries(t, callbackEntries)
  }
  
  func verifySelectiveBufferOutput(t *testing.T, logOutput string) {
  	t.Helper()
  	if !strings.Contains(logOutput, "[enforce]") {
  		t.Errorf("Expected log output to contain enforce events")
  	}
  	if !strings.Contains(logOutput, "[addPolicy]") {
  		t.Errorf("Expected log output to contain addPolicy event")
  	}
  	if strings.Contains(logOutput, "[removePolicy]") {
  		t.Errorf("Did not expect log output to contain removePolicy event")
  	}
  	if strings.Contains(logOutput, "[loadPolicy]") {
  		t.Errorf("Did not expect log output to contain loadPolicy event")
  	}
  }
  
  func verifySelectiveCallbackEntries(t *testing.T, entries []*log.LogEntry) {
  	t.Helper()
  	found := map[log.EventType]bool{}
  
  	for _, entry := range entries {
  		found[entry.EventType] = true
  		checkEntryActiveStatus(t, entry)
  	}
  
  	requiredEvents := []log.EventType{
  		log.EventEnforce, log.EventAddPolicy, log.EventRemovePolicy, log.EventLoadPolicy,
  	}
  	for _, eventType := range requiredEvents {
  		if !found[eventType] {
  			t.Errorf("Expected to find %s in callback entries", eventType)
  		}
  	}
  }
  
  func checkEntryActiveStatus(t *testing.T, entry *log.LogEntry) {
  	t.Helper()
  	switch entry.EventType {
  	case log.EventEnforce, log.EventAddPolicy:
  		if !entry.IsActive {
  			t.Errorf("Expected %s entry to be active", entry.EventType)
  		}
  	case log.EventRemovePolicy, log.EventLoadPolicy:
  		if entry.IsActive {
  			t.Errorf("Expected %s entry to be inactive", entry.EventType)
  		}
  	case log.EventSavePolicy:
  		// SavePolicy event exists but we're not checking it in this test
  	}
  }
  