315 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
| package phpfpm
 | |
| 
 | |
| import (
 | |
| 	"crypto/rand"
 | |
| 	"encoding/binary"
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"net/http/fcgi"
 | |
| 	"net/http/httptest"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/influxdata/telegraf/testutil"
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| 	"github.com/stretchr/testify/require"
 | |
| )
 | |
| 
 | |
| type statServer struct{}
 | |
| 
 | |
| // We create a fake server to return test data
 | |
| func (s statServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | |
| 	w.Header().Set("Content-Type", "text/plain")
 | |
| 	w.Header().Set("Content-Length", fmt.Sprint(len(outputSample)))
 | |
| 	fmt.Fprint(w, outputSample)
 | |
| }
 | |
| 
 | |
| func TestPhpFpmGeneratesMetrics_From_Http(t *testing.T) {
 | |
| 	sv := statServer{}
 | |
| 	ts := httptest.NewServer(sv)
 | |
| 	defer ts.Close()
 | |
| 
 | |
| 	r := &phpfpm{
 | |
| 		Urls: []string{ts.URL},
 | |
| 	}
 | |
| 
 | |
| 	var acc testutil.Accumulator
 | |
| 
 | |
| 	err := acc.GatherError(r.Gather)
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	tags := map[string]string{
 | |
| 		"pool": "www",
 | |
| 		"url":  ts.URL,
 | |
| 	}
 | |
| 
 | |
| 	fields := map[string]interface{}{
 | |
| 		"start_since":          int64(1991),
 | |
| 		"accepted_conn":        int64(3),
 | |
| 		"listen_queue":         int64(1),
 | |
| 		"max_listen_queue":     int64(0),
 | |
| 		"listen_queue_len":     int64(0),
 | |
| 		"idle_processes":       int64(1),
 | |
| 		"active_processes":     int64(1),
 | |
| 		"total_processes":      int64(2),
 | |
| 		"max_active_processes": int64(1),
 | |
| 		"max_children_reached": int64(2),
 | |
| 		"slow_requests":        int64(1),
 | |
| 	}
 | |
| 
 | |
| 	acc.AssertContainsTaggedFields(t, "phpfpm", fields, tags)
 | |
| }
 | |
| 
 | |
| func TestPhpFpmGeneratesMetrics_From_Fcgi(t *testing.T) {
 | |
| 	// Let OS find an available port
 | |
| 	tcp, err := net.Listen("tcp", "127.0.0.1:0")
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Cannot initialize test server")
 | |
| 	}
 | |
| 	defer tcp.Close()
 | |
| 
 | |
| 	s := statServer{}
 | |
| 	go fcgi.Serve(tcp, s)
 | |
| 
 | |
| 	//Now we tested again above server
 | |
| 	r := &phpfpm{
 | |
| 		Urls: []string{"fcgi://" + tcp.Addr().String() + "/status"},
 | |
| 	}
 | |
| 
 | |
| 	var acc testutil.Accumulator
 | |
| 	err = acc.GatherError(r.Gather)
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	tags := map[string]string{
 | |
| 		"pool": "www",
 | |
| 		"url":  r.Urls[0],
 | |
| 	}
 | |
| 
 | |
| 	fields := map[string]interface{}{
 | |
| 		"start_since":          int64(1991),
 | |
| 		"accepted_conn":        int64(3),
 | |
| 		"listen_queue":         int64(1),
 | |
| 		"max_listen_queue":     int64(0),
 | |
| 		"listen_queue_len":     int64(0),
 | |
| 		"idle_processes":       int64(1),
 | |
| 		"active_processes":     int64(1),
 | |
| 		"total_processes":      int64(2),
 | |
| 		"max_active_processes": int64(1),
 | |
| 		"max_children_reached": int64(2),
 | |
| 		"slow_requests":        int64(1),
 | |
| 	}
 | |
| 
 | |
| 	acc.AssertContainsTaggedFields(t, "phpfpm", fields, tags)
 | |
| }
 | |
| 
 | |
| func TestPhpFpmGeneratesMetrics_From_Socket(t *testing.T) {
 | |
| 	// Create a socket in /tmp because we always have write permission and if the
 | |
| 	// removing of socket fail when system restart /tmp is clear so
 | |
| 	// we don't have junk files around
 | |
| 	var randomNumber int64
 | |
| 	binary.Read(rand.Reader, binary.LittleEndian, &randomNumber)
 | |
| 	tcp, err := net.Listen("unix", fmt.Sprintf("/tmp/test-fpm%d.sock", randomNumber))
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Cannot initialize server on port ")
 | |
| 	}
 | |
| 
 | |
| 	defer tcp.Close()
 | |
| 	s := statServer{}
 | |
| 	go fcgi.Serve(tcp, s)
 | |
| 
 | |
| 	r := &phpfpm{
 | |
| 		Urls: []string{tcp.Addr().String()},
 | |
| 	}
 | |
| 
 | |
| 	var acc testutil.Accumulator
 | |
| 
 | |
| 	err = acc.GatherError(r.Gather)
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	tags := map[string]string{
 | |
| 		"pool": "www",
 | |
| 		"url":  r.Urls[0],
 | |
| 	}
 | |
| 
 | |
| 	fields := map[string]interface{}{
 | |
| 		"start_since":          int64(1991),
 | |
| 		"accepted_conn":        int64(3),
 | |
| 		"listen_queue":         int64(1),
 | |
| 		"max_listen_queue":     int64(0),
 | |
| 		"listen_queue_len":     int64(0),
 | |
| 		"idle_processes":       int64(1),
 | |
| 		"active_processes":     int64(1),
 | |
| 		"total_processes":      int64(2),
 | |
| 		"max_active_processes": int64(1),
 | |
| 		"max_children_reached": int64(2),
 | |
| 		"slow_requests":        int64(1),
 | |
| 	}
 | |
| 
 | |
| 	acc.AssertContainsTaggedFields(t, "phpfpm", fields, tags)
 | |
| }
 | |
| 
 | |
| func TestPhpFpmGeneratesMetrics_From_Multiple_Sockets_With_Glob(t *testing.T) {
 | |
| 	// Create a socket in /tmp because we always have write permission and if the
 | |
| 	// removing of socket fail when system restart /tmp is clear so
 | |
| 	// we don't have junk files around
 | |
| 	var randomNumber int64
 | |
| 	binary.Read(rand.Reader, binary.LittleEndian, &randomNumber)
 | |
| 	socket1 := fmt.Sprintf("/tmp/test-fpm%d.sock", randomNumber)
 | |
| 	tcp1, err := net.Listen("unix", socket1)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Cannot initialize server on port ")
 | |
| 	}
 | |
| 	defer tcp1.Close()
 | |
| 
 | |
| 	binary.Read(rand.Reader, binary.LittleEndian, &randomNumber)
 | |
| 	socket2 := fmt.Sprintf("/tmp/test-fpm%d.sock", randomNumber)
 | |
| 	tcp2, err := net.Listen("unix", socket2)
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Cannot initialize server on port ")
 | |
| 	}
 | |
| 	defer tcp2.Close()
 | |
| 
 | |
| 	s := statServer{}
 | |
| 	go fcgi.Serve(tcp1, s)
 | |
| 	go fcgi.Serve(tcp2, s)
 | |
| 
 | |
| 	r := &phpfpm{
 | |
| 		Urls: []string{"/tmp/test-fpm[\\-0-9]*.sock"},
 | |
| 	}
 | |
| 
 | |
| 	var acc1, acc2 testutil.Accumulator
 | |
| 
 | |
| 	err = acc1.GatherError(r.Gather)
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	err = acc2.GatherError(r.Gather)
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	tags1 := map[string]string{
 | |
| 		"pool": "www",
 | |
| 		"url":  socket1,
 | |
| 	}
 | |
| 
 | |
| 	tags2 := map[string]string{
 | |
| 		"pool": "www",
 | |
| 		"url":  socket2,
 | |
| 	}
 | |
| 
 | |
| 	fields := map[string]interface{}{
 | |
| 		"start_since":          int64(1991),
 | |
| 		"accepted_conn":        int64(3),
 | |
| 		"listen_queue":         int64(1),
 | |
| 		"max_listen_queue":     int64(0),
 | |
| 		"listen_queue_len":     int64(0),
 | |
| 		"idle_processes":       int64(1),
 | |
| 		"active_processes":     int64(1),
 | |
| 		"total_processes":      int64(2),
 | |
| 		"max_active_processes": int64(1),
 | |
| 		"max_children_reached": int64(2),
 | |
| 		"slow_requests":        int64(1),
 | |
| 	}
 | |
| 
 | |
| 	acc1.AssertContainsTaggedFields(t, "phpfpm", fields, tags1)
 | |
| 	acc2.AssertContainsTaggedFields(t, "phpfpm", fields, tags2)
 | |
| }
 | |
| 
 | |
| func TestPhpFpmGeneratesMetrics_From_Socket_Custom_Status_Path(t *testing.T) {
 | |
| 	// Create a socket in /tmp because we always have write permission. If the
 | |
| 	// removing of socket fail we won't have junk files around. Cuz when system
 | |
| 	// restart, it clears out /tmp
 | |
| 	var randomNumber int64
 | |
| 	binary.Read(rand.Reader, binary.LittleEndian, &randomNumber)
 | |
| 	tcp, err := net.Listen("unix", fmt.Sprintf("/tmp/test-fpm%d.sock", randomNumber))
 | |
| 	if err != nil {
 | |
| 		t.Fatal("Cannot initialize server on port ")
 | |
| 	}
 | |
| 
 | |
| 	defer tcp.Close()
 | |
| 	s := statServer{}
 | |
| 	go fcgi.Serve(tcp, s)
 | |
| 
 | |
| 	r := &phpfpm{
 | |
| 		Urls: []string{tcp.Addr().String() + ":custom-status-path"},
 | |
| 	}
 | |
| 
 | |
| 	var acc testutil.Accumulator
 | |
| 
 | |
| 	err = acc.GatherError(r.Gather)
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	tags := map[string]string{
 | |
| 		"pool": "www",
 | |
| 		"url":  r.Urls[0],
 | |
| 	}
 | |
| 
 | |
| 	fields := map[string]interface{}{
 | |
| 		"start_since":          int64(1991),
 | |
| 		"accepted_conn":        int64(3),
 | |
| 		"listen_queue":         int64(1),
 | |
| 		"max_listen_queue":     int64(0),
 | |
| 		"listen_queue_len":     int64(0),
 | |
| 		"idle_processes":       int64(1),
 | |
| 		"active_processes":     int64(1),
 | |
| 		"total_processes":      int64(2),
 | |
| 		"max_active_processes": int64(1),
 | |
| 		"max_children_reached": int64(2),
 | |
| 		"slow_requests":        int64(1),
 | |
| 	}
 | |
| 
 | |
| 	acc.AssertContainsTaggedFields(t, "phpfpm", fields, tags)
 | |
| }
 | |
| 
 | |
| //When not passing server config, we default to localhost
 | |
| //We just want to make sure we did request stat from localhost
 | |
| func TestPhpFpmDefaultGetFromLocalhost(t *testing.T) {
 | |
| 	r := &phpfpm{}
 | |
| 
 | |
| 	var acc testutil.Accumulator
 | |
| 
 | |
| 	err := acc.GatherError(r.Gather)
 | |
| 	require.Error(t, err)
 | |
| 	assert.Contains(t, err.Error(), "127.0.0.1/status")
 | |
| }
 | |
| 
 | |
| func TestPhpFpmGeneratesMetrics_Throw_Error_When_Fpm_Status_Is_Not_Responding(t *testing.T) {
 | |
| 	r := &phpfpm{
 | |
| 		Urls: []string{"http://aninvalidone"},
 | |
| 	}
 | |
| 
 | |
| 	var acc testutil.Accumulator
 | |
| 
 | |
| 	err := acc.GatherError(r.Gather)
 | |
| 	require.Error(t, err)
 | |
| 	assert.Contains(t, err.Error(), `Unable to connect to phpfpm status page 'http://aninvalidone': Get http://aninvalidone: dial tcp: lookup aninvalidone`)
 | |
| }
 | |
| 
 | |
| func TestPhpFpmGeneratesMetrics_Throw_Error_When_Socket_Path_Is_Invalid(t *testing.T) {
 | |
| 	r := &phpfpm{
 | |
| 		Urls: []string{"/tmp/invalid.sock"},
 | |
| 	}
 | |
| 
 | |
| 	var acc testutil.Accumulator
 | |
| 
 | |
| 	err := acc.GatherError(r.Gather)
 | |
| 	require.Error(t, err)
 | |
| 	assert.Equal(t, `dial unix /tmp/invalid.sock: connect: no such file or directory`, err.Error())
 | |
| 
 | |
| }
 | |
| 
 | |
| const outputSample = `
 | |
| pool:                 www
 | |
| process manager:      dynamic
 | |
| start time:           11/Oct/2015:23:38:51 +0000
 | |
| start since:          1991
 | |
| accepted conn:        3
 | |
| listen queue:         1
 | |
| max listen queue:     0
 | |
| listen queue len:     0
 | |
| idle processes:       1
 | |
| active processes:     1
 | |
| total processes:      2
 | |
| max active processes: 1
 | |
| max children reached: 2
 | |
| slow requests:        1
 | |
| `
 |