mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-06-19 07:36:59 +00:00
72932f4a6c
* fix: prevent duplicate include directives in nginx.conf The FixNginxConfIncludeSites, FixNginxConfIncludeStreams, and FixNginxConfIncludeConfD functions now check if the include directive already exists before adding a new one. This prevents duplicate include directives that could cause nginx to load configurations twice, leading to errors like 'duplicate upstream' in stream configurations. Fixes the issue where stream and http includes were being added multiple times to nginx.conf: - include /etc/nginx/sites-enabled/*; - include /etc/nginx/streams-enabled/*; - include /etc/nginx/conf.d/*.conf; Added test TestFixNginxConfNoDuplicateIncludes to verify the fix. Co-authored-by: Jacky <me@jackyu.cn> * fix: align Fix function patterns with Check functions and defer backup creation - Change Fix functions to use same glob patterns as Check functions: - 'sites-enabled/*' instead of 'sites-enabled' - 'streams-enabled/*' instead of 'streams-enabled' - 'conf.d/*' instead of 'conf.d' - Move backup file creation after the duplicate check to avoid creating unnecessary backup files when no changes are needed This fixes two issues: 1. Fix functions would incorrectly skip adding includes when a non-glob include existed (e.g., conf.d/default.conf) 2. Backup files were created even when early-returning due to duplicate detection * Fix: Add backup creation for fallback paths in nginx.conf fix functions The backup creation was moved inside the block-found branch, but the fallback paths (when no http/stream block exists) still write to the file without creating a backup first. This fix adds backup creation before each fallback write operation to restore the original behavior where all code paths that modify the file are protected by a backup. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
176 lines
5.9 KiB
Go
176 lines
5.9 KiB
Go
package self_check
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/0xJacky/Nginx-UI/settings"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/uozi-tech/cosy"
|
|
"github.com/uozi-tech/cosy/logger"
|
|
)
|
|
|
|
func TestCheckNginxConfIncludeSites(t *testing.T) {
|
|
// test ok
|
|
logger.Init("debug")
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/ok.conf"
|
|
var result *cosy.Error
|
|
errors.As(CheckNginxConfIncludeSites(), &result)
|
|
assert.Nil(t, result)
|
|
|
|
// test 4041 nginx.conf not found
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/4041.conf"
|
|
errors.As(CheckNginxConfIncludeSites(), &result)
|
|
assert.Equal(t, int32(40402), result.Code)
|
|
|
|
// test 5001 nginx.conf parse error
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/5001.conf"
|
|
errors.As(CheckNginxConfIncludeSites(), &result)
|
|
assert.Equal(t, int32(50001), result.Code)
|
|
|
|
// test 4042 nginx.conf no http block
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/no-http-block.conf"
|
|
errors.As(CheckNginxConfIncludeSites(), &result)
|
|
assert.Equal(t, int32(40403), result.Code)
|
|
|
|
// test 4043 nginx.conf not include sites-enabled
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/no-http-sites-enabled.conf"
|
|
errors.As(CheckNginxConfIncludeSites(), &result)
|
|
assert.Equal(t, int32(40404), result.Code)
|
|
}
|
|
|
|
func TestCheckNginxConfIncludeStreams(t *testing.T) {
|
|
// test ok
|
|
logger.Init("debug")
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/ok.conf"
|
|
var result *cosy.Error
|
|
errors.As(CheckNginxConfIncludeStreams(), &result)
|
|
assert.Nil(t, result)
|
|
|
|
// test 4041 nginx.conf not found
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/4041.conf"
|
|
errors.As(CheckNginxConfIncludeStreams(), &result)
|
|
assert.Equal(t, int32(40402), result.Code)
|
|
|
|
// test 5001 nginx.conf parse error
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/5001.conf"
|
|
errors.As(CheckNginxConfIncludeStreams(), &result)
|
|
assert.Equal(t, int32(50001), result.Code)
|
|
|
|
// test 4044 nginx.conf no stream block
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/no-http-block.conf"
|
|
errors.As(CheckNginxConfIncludeStreams(), &result)
|
|
assert.Equal(t, int32(40405), result.Code)
|
|
|
|
// test 4045 nginx.conf not include stream-enabled
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
settings.NginxSettings.ConfigPath = "./test_cases/no-http-sites-enabled.conf"
|
|
errors.As(CheckNginxConfIncludeStreams(), &result)
|
|
assert.Equal(t, int32(40406), result.Code)
|
|
}
|
|
|
|
func TestFixNginxConfIncludeSites(t *testing.T) {
|
|
logger.Init("debug")
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
|
|
// copy file
|
|
content, err := os.ReadFile("./test_cases/no-http-block.conf")
|
|
assert.Nil(t, err)
|
|
|
|
err = os.WriteFile("./test_cases/no-http-block-fixed.conf", content, 0644)
|
|
assert.Nil(t, err)
|
|
|
|
settings.NginxSettings.ConfigPath = "./test_cases/no-http-block-fixed.conf"
|
|
var result *cosy.Error
|
|
errors.As(FixNginxConfIncludeSites(), &result)
|
|
assert.Nil(t, result)
|
|
|
|
// copy file
|
|
content, err = os.ReadFile("./test_cases/no-http-sites-enabled.conf")
|
|
assert.Nil(t, err)
|
|
err = os.WriteFile("./test_cases/no-http-sites-enabled-fixed.conf", content, 0644)
|
|
assert.Nil(t, err)
|
|
|
|
settings.NginxSettings.ConfigPath = "./test_cases/no-http-sites-enabled-fixed.conf"
|
|
errors.As(FixNginxConfIncludeSites(), &result)
|
|
assert.Nil(t, result)
|
|
|
|
settings.NginxSettings.ConfigPath = "./test_cases/no-http-sites-enabled-fixed.conf"
|
|
errors.As(FixNginxConfIncludeStreams(), &result)
|
|
assert.Nil(t, result)
|
|
|
|
// remove backup files (./test_cases/*.bak.*)
|
|
files, err := os.ReadDir("./test_cases")
|
|
assert.Nil(t, err)
|
|
|
|
for _, file := range files {
|
|
if strings.Contains(file.Name(), ".bak.") {
|
|
err = os.Remove("./test_cases/" + file.Name())
|
|
assert.Nil(t, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFixNginxConfNoDuplicateIncludes(t *testing.T) {
|
|
logger.Init("debug")
|
|
settings.NginxSettings.ConfigDir = "/etc/nginx"
|
|
|
|
// copy ok.conf to test file (it already has all includes)
|
|
content, err := os.ReadFile("./test_cases/ok.conf")
|
|
assert.Nil(t, err)
|
|
|
|
testFile := "./test_cases/test-no-duplicate.conf"
|
|
err = os.WriteFile(testFile, content, 0644)
|
|
assert.Nil(t, err)
|
|
|
|
settings.NginxSettings.ConfigPath = testFile
|
|
var result *cosy.Error
|
|
|
|
// Call fix functions multiple times - should not create duplicates
|
|
for i := 0; i < 3; i++ {
|
|
errors.As(FixNginxConfIncludeSites(), &result)
|
|
assert.Nil(t, result, "FixNginxConfIncludeSites should not fail on iteration %d", i)
|
|
|
|
errors.As(FixNginxConfIncludeStreams(), &result)
|
|
assert.Nil(t, result, "FixNginxConfIncludeStreams should not fail on iteration %d", i)
|
|
|
|
errors.As(FixNginxConfIncludeConfD(), &result)
|
|
assert.Nil(t, result, "FixNginxConfIncludeConfD should not fail on iteration %d", i)
|
|
}
|
|
|
|
// Read the final content and verify no duplicates
|
|
finalContent, err := os.ReadFile(testFile)
|
|
assert.Nil(t, err)
|
|
|
|
// Count occurrences of include directives
|
|
sitesEnabledCount := strings.Count(string(finalContent), "sites-enabled")
|
|
streamsEnabledCount := strings.Count(string(finalContent), "streams-enabled")
|
|
confDCount := strings.Count(string(finalContent), "conf.d")
|
|
|
|
assert.Equal(t, 1, sitesEnabledCount, "sites-enabled should appear exactly once")
|
|
assert.Equal(t, 1, streamsEnabledCount, "streams-enabled should appear exactly once")
|
|
assert.Equal(t, 1, confDCount, "conf.d should appear exactly once")
|
|
|
|
// cleanup test file and backup files
|
|
_ = os.Remove(testFile)
|
|
files, err := os.ReadDir("./test_cases")
|
|
assert.Nil(t, err)
|
|
|
|
for _, file := range files {
|
|
if strings.Contains(file.Name(), ".bak.") || strings.Contains(file.Name(), "test-no-duplicate") {
|
|
_ = os.Remove("./test_cases/" + file.Name())
|
|
}
|
|
}
|
|
}
|