github.com/Ryan-Johnson-1315/socketlogger@v0.0.2/logger_test.go (about)

     1  package socketlogger
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"log"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strconv"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  var (
    17  	udpLoggerServer LoggerServer
    18  	udpLoggerClient LoggerClient
    19  	tcpLoggerServer LoggerServer
    20  	tcpLoggerClient LoggerClient
    21  	consoleOut      chan string
    22  	inputLines      []string
    23  	outputLines     []string
    24  	reader, writer  *os.File
    25  	longWait        int
    26  )
    27  
    28  const (
    29  	NUM_LINES  int           = 5000
    30  	udpTimeout time.Duration = 10 * time.Millisecond
    31  	// Account that TCP is a much slower socket
    32  	tcpTimeout time.Duration = 30 * time.Millisecond
    33  )
    34  
    35  func TestUDPLog(t *testing.T) {
    36  	capture()
    37  	failed := false
    38  	var now time.Time
    39  	for i := 0; i < NUM_LINES; i++ {
    40  		ticker := time.NewTicker(udpTimeout * time.Duration(longWait))
    41  		input := fmt.Sprintf("This is a testing message #%d -> TestUDPLog", i)
    42  		inputLines[i] = formatInput(input)
    43  		udpLoggerClient.Log(input)
    44  		select {
    45  		case line := <-consoleOut:
    46  			outputLines[i] = line
    47  			if failed {
    48  				closeWriters()
    49  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, udpTimeout, time.Since(now)+udpTimeout)
    50  				t.FailNow()
    51  			}
    52  		case <-ticker.C:
    53  			failed = true
    54  			now = time.Now()
    55  		}
    56  	}
    57  	closeWriters()
    58  	if correct, expected := checkOutput(); !correct {
    59  		t.Errorf("Lines did not match:%s", expected)
    60  		t.FailNow()
    61  	}
    62  }
    63  
    64  func TestUDPDbg(t *testing.T) {
    65  	capture()
    66  	failed := false
    67  	var now time.Time
    68  	for i := 0; i < NUM_LINES; i++ {
    69  		ticker := time.NewTicker(udpTimeout * time.Duration(longWait))
    70  		input := fmt.Sprintf("This is a testing message #%d -> TestUDPDbg", i)
    71  		inputLines[i] = formatInput(input)
    72  		udpLoggerClient.Dbg(input)
    73  		select {
    74  		case line := <-consoleOut:
    75  			outputLines[i] = line
    76  			if failed {
    77  				closeWriters()
    78  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, udpTimeout, time.Since(now)+udpTimeout)
    79  				t.FailNow()
    80  			}
    81  		case <-ticker.C:
    82  			failed = true
    83  			now = time.Now()
    84  		}
    85  	}
    86  	closeWriters()
    87  	if correct, expected := checkOutput(); !correct {
    88  		t.Errorf("Lines did not match:%s", expected)
    89  		t.FailNow()
    90  	}
    91  }
    92  
    93  func TestUDPWrn(t *testing.T) {
    94  	capture()
    95  	failed := false
    96  	var now time.Time
    97  	for i := 0; i < NUM_LINES; i++ {
    98  		ticker := time.NewTicker(udpTimeout * time.Duration(longWait))
    99  		input := fmt.Sprintf("This is a testing message #%d -> TestUDPWrn", i)
   100  		inputLines[i] = formatInput(input)
   101  		udpLoggerClient.Wrn(input)
   102  		select {
   103  		case line := <-consoleOut:
   104  			outputLines[i] = line
   105  			if failed {
   106  				closeWriters()
   107  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, udpTimeout, time.Since(now)+udpTimeout)
   108  				t.FailNow()
   109  			}
   110  		case <-ticker.C:
   111  			failed = true
   112  			now = time.Now()
   113  		}
   114  	}
   115  	closeWriters()
   116  	if correct, expected := checkOutput(); !correct {
   117  		t.Errorf("Lines did not match:%s", expected)
   118  		t.FailNow()
   119  	}
   120  }
   121  
   122  func TestUDPErr(t *testing.T) {
   123  	capture()
   124  	failed := false
   125  	var now time.Time
   126  	for i := 0; i < NUM_LINES; i++ {
   127  		ticker := time.NewTicker(udpTimeout * time.Duration(longWait))
   128  		input := fmt.Sprintf("This is a testing message #%d -> TestUDPErr", i)
   129  		inputLines[i] = formatInput(input)
   130  		udpLoggerClient.Err(input)
   131  		select {
   132  		case line := <-consoleOut:
   133  			outputLines[i] = line
   134  			if failed {
   135  				closeWriters()
   136  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, udpTimeout, time.Since(now)+udpTimeout)
   137  				t.FailNow()
   138  			}
   139  		case <-ticker.C:
   140  			failed = true
   141  			now = time.Now()
   142  		}
   143  	}
   144  	closeWriters()
   145  	if correct, expected := checkOutput(); !correct {
   146  		t.Errorf("Lines did not match:%s", expected)
   147  		t.FailNow()
   148  	}
   149  }
   150  
   151  func TestUDPSuccess(t *testing.T) {
   152  	capture()
   153  	failed := false
   154  	var now time.Time
   155  	for i := 0; i < NUM_LINES; i++ {
   156  		ticker := time.NewTicker(udpTimeout * time.Duration(longWait))
   157  		input := fmt.Sprintf("This is a testing message #%d -> TestUDPSuccess", i)
   158  		inputLines[i] = formatInput(input)
   159  		udpLoggerClient.Success(input)
   160  		select {
   161  		case line := <-consoleOut:
   162  			outputLines[i] = line
   163  			if failed {
   164  				closeWriters()
   165  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, udpTimeout, time.Since(now)+udpTimeout)
   166  				t.FailNow()
   167  			}
   168  		case <-ticker.C:
   169  			failed = true
   170  			now = time.Now()
   171  		}
   172  	}
   173  	closeWriters()
   174  	if correct, expected := checkOutput(); !correct {
   175  		t.Errorf("Lines did not match:%s", expected)
   176  		t.FailNow()
   177  	}
   178  }
   179  
   180  func TestTCPLog(t *testing.T) {
   181  	capture()
   182  	failed := false
   183  	var now time.Time
   184  	for i := 0; i < NUM_LINES; i++ {
   185  		ticker := time.NewTicker(tcpTimeout * time.Duration(longWait))
   186  		input := fmt.Sprintf("This is a testing message #%d -> TestTCPLog", i)
   187  		inputLines[i] = formatInput(input)
   188  		tcpLoggerClient.Log(input)
   189  		select {
   190  		case line := <-consoleOut:
   191  			outputLines[i] = line
   192  			if failed {
   193  				closeWriters()
   194  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, tcpTimeout, time.Since(now)+tcpTimeout)
   195  				t.FailNow()
   196  			}
   197  		case <-ticker.C:
   198  			failed = true
   199  			now = time.Now()
   200  		}
   201  	}
   202  	closeWriters()
   203  	if correct, expected := checkOutput(); !correct {
   204  		t.Errorf("Lines did not match:%s", expected)
   205  		t.FailNow()
   206  	}
   207  }
   208  
   209  func TestTCPDbg(t *testing.T) {
   210  	capture()
   211  	failed := false
   212  	var now time.Time
   213  	for i := 0; i < NUM_LINES; i++ {
   214  		ticker := time.NewTicker(tcpTimeout * time.Duration(longWait))
   215  		input := fmt.Sprintf("This is a testing message #%d -> TestTCPDbg", i)
   216  		inputLines[i] = formatInput(input)
   217  		tcpLoggerClient.Dbg(input)
   218  		select {
   219  		case line := <-consoleOut:
   220  			outputLines[i] = line
   221  			if failed {
   222  				closeWriters()
   223  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, tcpTimeout, time.Since(now)+tcpTimeout)
   224  				t.FailNow()
   225  			}
   226  		case <-ticker.C:
   227  			failed = true
   228  			now = time.Now()
   229  		}
   230  	}
   231  	closeWriters()
   232  	if correct, expected := checkOutput(); !correct {
   233  		t.Errorf("Lines did not match:%s", expected)
   234  		t.FailNow()
   235  	}
   236  }
   237  
   238  func TestTCPWrn(t *testing.T) {
   239  	capture()
   240  	failed := false
   241  	var now time.Time
   242  	for i := 0; i < NUM_LINES; i++ {
   243  		ticker := time.NewTicker(tcpTimeout * time.Duration(longWait))
   244  		input := fmt.Sprintf("This is a testing message #%d -> TestTCPWrn", i)
   245  		inputLines[i] = formatInput(input)
   246  		tcpLoggerClient.Wrn(input)
   247  		select {
   248  		case line := <-consoleOut:
   249  			outputLines[i] = line
   250  			if failed {
   251  				closeWriters()
   252  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, tcpTimeout, time.Since(now)+tcpTimeout)
   253  				t.FailNow()
   254  			}
   255  		case <-ticker.C:
   256  			failed = true
   257  			now = time.Now()
   258  		}
   259  	}
   260  	closeWriters()
   261  	if correct, expected := checkOutput(); !correct {
   262  		t.Errorf("Lines did not match:%s", expected)
   263  		t.FailNow()
   264  	}
   265  }
   266  
   267  func TestTCPErr(t *testing.T) {
   268  	capture()
   269  	failed := false
   270  	var now time.Time
   271  	for i := 0; i < NUM_LINES; i++ {
   272  		ticker := time.NewTicker(tcpTimeout * time.Duration(longWait))
   273  		input := fmt.Sprintf("This is a testing message #%d -> TestTCPErr", i)
   274  		inputLines[i] = formatInput(input)
   275  		tcpLoggerClient.Err(input)
   276  		select {
   277  		case line := <-consoleOut:
   278  			outputLines[i] = line
   279  			if failed {
   280  				closeWriters()
   281  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, tcpTimeout, time.Since(now)+tcpTimeout)
   282  				t.FailNow()
   283  			}
   284  		case <-ticker.C:
   285  			failed = true
   286  			now = time.Now()
   287  		}
   288  	}
   289  	closeWriters()
   290  	if correct, expected := checkOutput(); !correct {
   291  		t.Errorf("Lines did not match:%s", expected)
   292  		t.FailNow()
   293  	}
   294  }
   295  
   296  func TestTCPSuccess(t *testing.T) {
   297  	capture()
   298  	failed := false
   299  	var now time.Time
   300  	for i := 0; i < NUM_LINES; i++ {
   301  		ticker := time.NewTicker(tcpTimeout * time.Duration(longWait))
   302  		input := fmt.Sprintf("This is a testing message #%d -> TestTCPSuccess", i)
   303  		inputLines[i] = formatInput(input)
   304  		tcpLoggerClient.Success(input)
   305  		select {
   306  		case line := <-consoleOut:
   307  			outputLines[i] = line
   308  			if failed {
   309  				closeWriters()
   310  				t.Errorf("Message %d did not log in timeout period of %v. Actual:  %v", i, tcpTimeout, time.Since(now)+tcpTimeout)
   311  				t.FailNow()
   312  			}
   313  		case <-ticker.C:
   314  			failed = true
   315  			now = time.Now()
   316  		}
   317  	}
   318  	closeWriters()
   319  	if correct, expected := checkOutput(); !correct {
   320  		t.Errorf("Lines did not match:%s", expected)
   321  		t.FailNow()
   322  	}
   323  }
   324  
   325  func TestSetcpLoggerClientFile(t *testing.T) {
   326  	now := time.Now().Format("2006-01-02T15:04:05") + ".log"
   327  	dir := t.TempDir()
   328  	if err := logFile(NewUdpLoggerServer(), dir, now); err != "" {
   329  		t.Error(err)
   330  	}
   331  
   332  	if err := logFile(NewTcpLoggerServer(), dir, now); err != "" {
   333  		t.Error(err)
   334  	}
   335  
   336  	if err := logFile(NewTcpLoggerServer(), dir+"/not_there_yet", now); err != "" {
   337  		t.Error(err)
   338  	}
   339  
   340  	if err := logFile(NewUdpLoggerServer(), "/dev/should_fail", now); err == "" {
   341  		t.Error(err)
   342  	}
   343  }
   344  
   345  func TestMessageType(t *testing.T) {
   346  	if !checkMsgType(udpLoggerServer) {
   347  		t.Errorf("expected %T actual %T", &LogMessage{}, udpLoggerServer.getMessageType())
   348  	}
   349  
   350  	if !checkMsgType(tcpLoggerServer) {
   351  		t.Errorf("expected %T actual %T", &LogMessage{}, tcpLoggerServer.getMessageType())
   352  	}
   353  }
   354  
   355  func BenchmarkUDPLog(b *testing.B) {
   356  	for i := 0; i < NUM_LINES; i++ {
   357  		udpLoggerClient.Log("Benching with a long message %s", "***********************************************************************************")
   358  	}
   359  }
   360  
   361  func BenchmarkUDPDbg(b *testing.B) {
   362  	for i := 0; i < NUM_LINES; i++ {
   363  		udpLoggerClient.Dbg("Benching with a long message %s", "***********************************************************************************")
   364  	}
   365  }
   366  
   367  func BenchmarkUDPWrn(b *testing.B) {
   368  	for i := 0; i < NUM_LINES; i++ {
   369  		udpLoggerClient.Wrn("Benching with a long message %s", "***********************************************************************************")
   370  	}
   371  }
   372  
   373  func BenchmarkUDPErr(b *testing.B) {
   374  	for i := 0; i < NUM_LINES; i++ {
   375  		udpLoggerClient.Err("Benching with a long message %s", "***********************************************************************************")
   376  	}
   377  }
   378  
   379  func BenchmarkUDPSuccess(b *testing.B) {
   380  	for i := 0; i < NUM_LINES; i++ {
   381  		udpLoggerClient.Success("Benching with a long message %s", "***********************************************************************************")
   382  	}
   383  }
   384  
   385  func BenchmarkTCPLog(b *testing.B) {
   386  	for i := 0; i < NUM_LINES; i++ {
   387  		tcpLoggerClient.Log("Benching with a long message %s", "***********************************************************************************")
   388  	}
   389  }
   390  
   391  func BenchmarkTCPDbg(b *testing.B) {
   392  	for i := 0; i < NUM_LINES; i++ {
   393  		tcpLoggerClient.Dbg("Benching with a long message %s", "***********************************************************************************")
   394  	}
   395  }
   396  
   397  func BenchmarkTCPWrn(b *testing.B) {
   398  	for i := 0; i < NUM_LINES; i++ {
   399  		tcpLoggerClient.Wrn("Benching with a long message %s", "***********************************************************************************")
   400  	}
   401  }
   402  
   403  func BenchmarkTCPErr(b *testing.B) {
   404  	for i := 0; i < NUM_LINES; i++ {
   405  		tcpLoggerClient.Err("Benching with a long message %s", "***********************************************************************************")
   406  	}
   407  }
   408  
   409  func BenchmarkTCPSuccess(b *testing.B) {
   410  	for i := 0; i < NUM_LINES; i++ {
   411  		tcpLoggerClient.Success("Benching with a long message %s", "***********************************************************************************")
   412  	}
   413  }
   414  
   415  func TestTCPDisconnect(t *testing.T) {
   416  	server := NewTcpLoggerServer()
   417  	dir := t.TempDir()
   418  	server.SetLogFile(dir, "tcp_disconnect.log")
   419  	server.Bind(Connection{
   420  		Addr: "127.0.0.1",
   421  		Port: 43000,
   422  	})
   423  
   424  	logger := NewTcpLoggerClient()
   425  	logger.Connect(Connection{
   426  		Addr: "127.0.0.1",
   427  		Port: 0,
   428  	}, Connection{
   429  		Addr: "127.0.0.1",
   430  		Port: 43000,
   431  	})
   432  	expectedLines := 250
   433  	for i := 0; i < expectedLines; i++ {
   434  		logger.Log("TCP disconnect %d", i)
   435  	}
   436  
   437  	logger.Disconnect()                // Blocking
   438  	time.Sleep(500 * time.Millisecond) // Just enough to let the messages get to the server
   439  	server.Shutdown()                  // Blocking
   440  
   441  	dat, _ := os.ReadFile(filepath.Join(dir, "tcp_disconnect.log"))
   442  	lines := strings.Split(string(dat), "\n")
   443  
   444  	if len(lines) != expectedLines+4 { // +4 is the server and client and tcp disconnect output that gets written to the file, and the last newline after the split
   445  		t.Errorf("Output lines did not match expected. Expected: %d, Actual %d, %s", expectedLines+3, len(lines), filepath.Join(dir, "tcp_disconnect.log"))
   446  	}
   447  }
   448  
   449  func TestUDPDisconnect(t *testing.T) {
   450  	server := NewUdpLoggerServer()
   451  	dir := t.TempDir()
   452  	server.SetLogFile(dir, "udp_disconnect.log")
   453  	server.Bind(Connection{
   454  		Addr: "127.0.0.1",
   455  		Port: 43000,
   456  	})
   457  
   458  	logger := NewUdpLoggerClient()
   459  	logger.Connect(Connection{
   460  		Addr: "127.0.0.1",
   461  		Port: 0,
   462  	}, Connection{
   463  		Addr: "127.0.0.1",
   464  		Port: 43000,
   465  	})
   466  	expectedLines := 250
   467  	for i := 0; i < expectedLines; i++ {
   468  		logger.Log("UDP disconnect %d", i)
   469  	}
   470  
   471  	logger.Disconnect()                // Blocking
   472  	time.Sleep(500 * time.Millisecond) // Just enough to let the messages get to the server
   473  	server.Shutdown()                  // Blocking
   474  
   475  	dat, _ := os.ReadFile(filepath.Join(dir, "udp_disconnect.log"))
   476  	lines := strings.Split(string(dat), "\n")
   477  
   478  	if len(lines) != expectedLines+3 { // +3 is the server and client output that gets written to the file, and the last newline after the split
   479  		t.Errorf("Output lines did not match expected. Expected: %d, Actual %d, %s", expectedLines+3, len(lines), filepath.Join(dir, "udp_disconnect.log"))
   480  	}
   481  }
   482  
   483  func init() {
   484  	tcp := 60001
   485  	tcpLoggerServer = NewTcpLoggerServer()
   486  	tcpLoggerServer.SetTimeFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
   487  	tcpLoggerServer.Bind(Connection{
   488  		Addr: "127.0.0.1",
   489  		Port: tcp,
   490  	})
   491  
   492  	tcpLoggerClient = NewTcpLoggerClient()
   493  	tcpLoggerClient.Connect(Connection{
   494  		Addr: "127.0.0.1",
   495  		Port: 0,
   496  	}, Connection{
   497  		Addr: "127.0.0.1",
   498  		Port: tcp,
   499  	})
   500  
   501  	udp := 60000
   502  	udpLoggerServer = NewUdpLoggerServer()
   503  	udpLoggerServer.SetTimeFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
   504  	udpLoggerServer.Bind(Connection{
   505  		Addr: "127.0.0.1",
   506  		Port: udp,
   507  	})
   508  
   509  	udpLoggerClient = NewUdpLoggerClient()
   510  	udpLoggerClient.Connect(Connection{
   511  		Addr: "127.0.0.1",
   512  		Port: 0,
   513  	}, Connection{
   514  		Addr: "127.0.0.1",
   515  		Port: udp,
   516  	})
   517  
   518  	consoleOut = make(chan string, 25)
   519  	inputLines = make([]string, NUM_LINES)
   520  	outputLines = make([]string, NUM_LINES)
   521  	time.Sleep(100 * time.Millisecond)
   522  	log.Println("Multiplying wait time by", os.Getenv("LONG_WAIT"))
   523  	if env := os.Getenv("LONG_WAIT"); env != "" {
   524  		var err error
   525  		longWait, err = strconv.Atoi(env)
   526  		if err != nil {
   527  			log.Fatal(err)
   528  		}
   529  	} else {
   530  		longWait = 1
   531  	}
   532  }
   533  
   534  func capture() {
   535  	var err error
   536  
   537  	reader, writer, err = os.Pipe()
   538  	if err != nil {
   539  		panic(err)
   540  	}
   541  
   542  	stdout := os.Stdout
   543  	stderr := os.Stderr
   544  
   545  	os.Stderr = writer
   546  	os.Stdout = writer
   547  	log.SetOutput(writer)
   548  
   549  	go func() {
   550  		scanner := bufio.NewScanner(reader)
   551  		for scanner.Scan() {
   552  			consoleOut <- scanner.Text()
   553  		}
   554  
   555  		os.Stdout = stdout
   556  		os.Stderr = stderr
   557  	}()
   558  	time.Sleep(50 * time.Millisecond) // Reset everything
   559  }
   560  
   561  func closeWriters() {
   562  	writer.Close()
   563  	reader.Close()
   564  }
   565  
   566  func checkOutput() (bool, string) {
   567  	closeWriters()
   568  	success := true
   569  	expected := ""
   570  	for i, fullLine := range outputLines {
   571  		output := strings.Split(fullLine, "| ")[1]
   572  		if same := strings.Compare(output, inputLines[i]); same != 0 {
   573  			success = false
   574  			expected = fmt.Sprintf(`
   575  Output:   "%s"
   576  Expected: "%s"`, strings.TrimSuffix(output, "\n"), inputLines[i])
   577  			break
   578  		}
   579  	}
   580  	return success, expected
   581  }
   582  
   583  func formatInput(msg string) string {
   584  	_, file, line, _ := runtime.Caller(1)
   585  	paths := strings.Split(file, "/")
   586  	file = paths[len(paths)-1]
   587  	return fmt.Sprintf("%s:%d -- %s", file, line+1, msg) + string(reset)
   588  }
   589  
   590  func logFile(server LoggerServer, dir, fname string) string {
   591  	msg := ""
   592  	server.SetLogFile(dir, fname)
   593  
   594  	if !fileDirExists(dir, fname) {
   595  		msg = fmt.Sprintf("%s log file was not created", filepath.Join(dir, fname))
   596  	}
   597  	return msg
   598  }
   599  
   600  func checkMsgType(server LoggerServer) bool {
   601  	switch server.getMessageType().(type) {
   602  	case *LogMessage:
   603  		return true
   604  	default:
   605  		return false
   606  	}
   607  }