Repository: moby/moby
File: daemon/logger/fluentd/fluentd_test.go (Go)

Code before:
	}
	for k, v := range validDurations {
		t.Run("valid "+k, func(t *testing.T) {
			err := ValidateLogOpt(map[string]string{writeTimeoutKey: k})
			assert.NilError(t, err)
			// Ignore err here since that's already checked in the ValidateLogOpt error check.
			cfg, _ := parseConfig(map[string]string{writeTimeoutKey: k})
			assert.Equal(t, cfg.WriteTimeout, v)
		})
	}
}

// TestWriteTimeoutIsEffective tests that writes timeout when the server is unresponsive.
// The test ensures that instead of hanging forever, the fluentd write operation returns
// an error when writes cannot be completed within the specified duration.
func TestWriteTimeoutIsEffective(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip("windows not supported")
	}

	socketFile := "/tmp/fluent-logger-golang.sock"
	l, err := net.Listen("unix", socketFile)
	assert.NilError(t, err, "unable to create listener for socket %s", socketFile)
	defer l.Close()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	var connectedWG sync.WaitGroup
	connectedWG.Add(1)

	// Start accepting connections.
	go func(ctx context.Context, wg *sync.WaitGroup) {
		wg.Done()

		for {
			conn, err := l.Accept()
			if err != nil {
				// Unable to process the connection. This can happen if the connection is closed.
				select {
				case <-ctx.Done():
					// If the context is canceled, there's nothing for us to do here.
					return
				default:
					t.Logf("Unable to accept connection: %v", err)
					continue
				}
			}

			// Handle an incoming connection. We're essentially blackholing this by not reading from
			// or writing to the connection.

Review comment (suggestion):
I was trying the test with the option disabled, and that caused it (expectedly) to hang forever; perhaps we should add a timeout here .. just in case?


```go
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
```

Code after:
		"":      0,
	}
	for k, v := range validDurations {
		t.Run("valid "+k, func(t *testing.T) {
			err := ValidateLogOpt(map[string]string{writeTimeoutKey: k})
			assert.NilError(t, err)
			cfg, err := parseConfig(map[string]string{writeTimeoutKey: k})
			// This check is mostly redundant since it's checked in ValidateLogOpt as well.
			// This is here to guard against potential regressions in the future.
			assert.NilError(t, err)
			assert.Equal(t, cfg.WriteTimeout, v)
		})
	}
}

// TestWriteTimeoutIsEffective tests that writes timeout when the server is unresponsive.
// The test ensures that instead of hanging forever, the fluentd write operation returns
// an error when writes cannot be completed within the specified duration.
func TestWriteTimeoutIsEffective(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip("windows not supported")
	}

	// Create a temporary directory for the socket file
	tmpDir := t.TempDir()
	socketFile := filepath.Join(tmpDir, "fluent-logger-golang.sock")
	l, err := net.Listen("unix", socketFile)
	assert.NilError(t, err, "unable to create listener for socket %s", socketFile)
	defer l.Close()

	// This is to guard against potential run-away test scenario so that a future change
	// doesn't cause the tests suite to timeout. It "fluentd-write-timeout" is not set, this
	// test will be blocked on the socket write operation. The timeout guards against that.
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	var connectedWG sync.WaitGroup
	connectedWG.Add(1)

	// Start accepting connections.
	go func(ctx context.Context, wg *sync.WaitGroup) {
		wg.Done()

		for {
			conn, err := l.Accept()
			if err != nil {
				// Unable to process the connection. This can happen if the connection is closed.
				select {
				case <-ctx.Done():
					// If the context is canceled, there's nothing for us to do here.
					return