| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 | package nginx_logimport (	"testing")// TestScanForLogDirectivesRemoval tests that removed log directives are properly cleaned upfunc TestScanForLogDirectivesRemoval(t *testing.T) {	// Clear cache before test	ClearLogCache()	configPath := "/etc/nginx/sites-available/test.conf"	// First scan with two log directives	content1 := []byte(`server {    listen 80;    server_name example.com;        access_log /var/log/nginx/access.log;    error_log /var/log/nginx/error.log;}`)	err := scanForLogDirectives(configPath, content1)	if err != nil {		t.Fatalf("First scan failed: %v", err)	}	// Check that both logs are cached	logs := GetAllLogPaths()	if len(logs) != 2 {		t.Fatalf("Expected 2 logs after first scan, got %d", len(logs))	}	// Verify the config file is tracked	accessFound := false	errorFound := false	for _, log := range logs {		if log.ConfigFile != configPath {			t.Errorf("Expected config file %s, got %s", configPath, log.ConfigFile)		}		if log.Type == "access" {			accessFound = true		}		if log.Type == "error" {			errorFound = true		}	}	if !accessFound || !errorFound {		t.Error("Expected both access and error logs to be found")	}	// Second scan with only one log directive (error_log removed)	content2 := []byte(`server {    listen 80;    server_name example.com;        access_log /var/log/nginx/access.log;}`)	err = scanForLogDirectives(configPath, content2)	if err != nil {		t.Fatalf("Second scan failed: %v", err)	}	// Check that only access log remains	logs = GetAllLogPaths()	if len(logs) != 1 {		t.Fatalf("Expected 1 log after second scan, got %d", len(logs))	}	if logs[0].Type != "access" {		t.Errorf("Expected remaining log to be access log, got %s", logs[0].Type)	}	// Third scan with no log directives	content3 := []byte(`server {    listen 80;    server_name example.com;}`)	err = scanForLogDirectives(configPath, content3)	if err != nil {		t.Fatalf("Third scan failed: %v", err)	}	// Check that no logs remain	logs = GetAllLogPaths()	if len(logs) != 0 {		t.Fatalf("Expected 0 logs after third scan, got %d", len(logs))	}}// TestScanForLogDirectivesMultipleConfigs tests that logs from different config files are handled independentlyfunc TestScanForLogDirectivesMultipleConfigs(t *testing.T) {	// Clear cache before test	ClearLogCache()	configPath1 := "/etc/nginx/sites-available/site1.conf"	configPath2 := "/etc/nginx/sites-available/site2.conf"	// Scan first config	content1 := []byte(`server {    listen 80;    server_name site1.com;    access_log /var/log/nginx/site1_access.log;}`)	err := scanForLogDirectives(configPath1, content1)	if err != nil {		t.Fatalf("First config scan failed: %v", err)	}	// Scan second config	content2 := []byte(`server {    listen 80;    server_name site2.com;    access_log /var/log/nginx/site2_access.log;}`)	err = scanForLogDirectives(configPath2, content2)	if err != nil {		t.Fatalf("Second config scan failed: %v", err)	}	// Should have 2 logs total	logs := GetAllLogPaths()	if len(logs) != 2 {		t.Fatalf("Expected 2 logs from 2 configs, got %d", len(logs))	}	// Remove log from first config, should only affect that config	emptyContent := []byte(`server {    listen 80;    server_name site1.com;}`)	err = scanForLogDirectives(configPath1, emptyContent)	if err != nil {		t.Fatalf("Empty config scan failed: %v", err)	}	// Should have 1 log remaining (from config2)	logs = GetAllLogPaths()	if len(logs) != 1 {		t.Fatalf("Expected 1 log after removing from config1, got %d", len(logs))	}	if logs[0].ConfigFile != configPath2 {		t.Errorf("Expected remaining log to be from config2 (%s), got %s", configPath2, logs[0].ConfigFile)	}}// TestScanForLogDirectivesIgnoreComments tests that commented log directives are ignoredfunc TestScanForLogDirectivesIgnoreComments(t *testing.T) {	// Clear cache before test	ClearLogCache()	configPath := "/etc/nginx/sites-available/test.conf"	// Content with both active and commented log directives	content := []byte(`server {    listen 80;    server_name example.com;        # This is a commented access log - should be ignored    # access_log /var/log/nginx/commented_access.log;        # Multi-line comment block    #error_log /var/log/nginx/commented_error.log;        # Active log directives (not commented)    access_log /var/log/nginx/active_access.log;    error_log /var/log/nginx/active_error.log;        # Another commented directive with indentation        # access_log /var/log/nginx/indented_comment.log;        # Inline comment after directive should still work    access_log /var/log/nginx/inline_comment.log; # this is active with comment}`)	err := scanForLogDirectives(configPath, content)	if err != nil {		t.Fatalf("Scan failed: %v", err)	}	// Should only find 3 active log directives (not the commented ones)	logs := GetAllLogPaths()	expectedCount := 3	if len(logs) != expectedCount {		t.Fatalf("Expected %d logs, got %d. Logs found: %+v", expectedCount, len(logs), logs)	}	// Verify the correct paths were found	expectedPaths := map[string]bool{		"/var/log/nginx/active_access.log":  false,		"/var/log/nginx/active_error.log":   false,		"/var/log/nginx/inline_comment.log": false,	}	for _, log := range logs {		if _, exists := expectedPaths[log.Path]; !exists {			t.Errorf("Unexpected log path found: %s", log.Path)		} else {			expectedPaths[log.Path] = true		}	}	// Check that all expected paths were found	for path, found := range expectedPaths {		if !found {			t.Errorf("Expected log path not found: %s", path)		}	}	// Verify no commented paths were included	commentedPaths := []string{		"/var/log/nginx/commented_access.log",		"/var/log/nginx/commented_error.log",		"/var/log/nginx/indented_comment.log",	}	for _, log := range logs {		for _, commentedPath := range commentedPaths {			if log.Path == commentedPath {				t.Errorf("Commented log path should not be included: %s", commentedPath)			}		}	}}// TestLogDirectiveRegex tests the regex pattern and comment filtering logicfunc TestLogDirectiveRegex(t *testing.T) {	testCases := []struct {		name           string		content        string		expectedActive int // number of active (non-commented) matches expected	}{		{			name:           "Active directives",			content:        "access_log /var/log/nginx/access.log;\nerror_log /var/log/nginx/error.log;",			expectedActive: 2,		},		{			name:           "Commented directives",			content:        "# access_log /var/log/nginx/access.log;\n#error_log /var/log/nginx/error.log;",			expectedActive: 0,		},		{			name:           "Mixed active and commented",			content:        "access_log /var/log/nginx/access.log;\n# error_log /var/log/nginx/error.log;",			expectedActive: 1,		},		{			name:           "Indented comments",			content:        "    # access_log /var/log/nginx/access.log;\n    error_log /var/log/nginx/error.log;",			expectedActive: 1,		},		{			name:           "Inline comments after directive",			content:        "access_log /var/log/nginx/access.log; # this is a comment",			expectedActive: 1,		},	}	for _, tc := range testCases {		t.Run(tc.name, func(t *testing.T) {			// Find all matches using the regex			matches := logDirectiveRegex.FindAllSubmatch([]byte(tc.content), -1)			// Count how many are not commented			activeCount := 0			for _, match := range matches {				if !isCommentedMatch([]byte(tc.content), match) {					activeCount++				}			}			if activeCount != tc.expectedActive {				t.Errorf("Test '%s': expected %d active matches, got %d. Content: %s",					tc.name, tc.expectedActive, activeCount, tc.content)			}		})	}}// TestIsCommentedMatch tests the isCommentedMatch function directlyfunc TestIsCommentedMatch(t *testing.T) {	testCases := []struct {		name        string		content     string		matchStr    string		isCommented bool	}{		{			name:        "Not commented",			content:     "access_log /var/log/nginx/access.log;",			matchStr:    "access_log /var/log/nginx/access.log;",			isCommented: false,		},		{			name:        "Commented with #",			content:     "# access_log /var/log/nginx/access.log;",			matchStr:    "access_log /var/log/nginx/access.log;",			isCommented: true,		},		{			name:        "Commented with spaces and #",			content:     "    # access_log /var/log/nginx/access.log;",			matchStr:    "access_log /var/log/nginx/access.log;",			isCommented: true,		},		{			name:        "Not commented with spaces",			content:     "    access_log /var/log/nginx/access.log;",			matchStr:    "access_log /var/log/nginx/access.log;",			isCommented: false,		},		{			name:        "Inline comment after directive",			content:     "access_log /var/log/nginx/access.log; # comment",			matchStr:    "access_log /var/log/nginx/access.log;",			isCommented: false,		},	}	for _, tc := range testCases {		t.Run(tc.name, func(t *testing.T) {			// Create a fake match to test with			match := [][]byte{[]byte(tc.matchStr)}			result := isCommentedMatch([]byte(tc.content), match)			if result != tc.isCommented {				t.Errorf("Test '%s': expected isCommented=%v, got %v. Content: %q, Match: %q",					tc.name, tc.isCommented, result, tc.content, tc.matchStr)			}		})	}}
 |