github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/logger/splunk/splunk_test.go (about)

     1  package splunk // import "github.com/docker/docker/daemon/logger/splunk"
     2  
     3  import (
     4  	"compress/gzip"
     5  	"context"
     6  	"fmt"
     7  	"net/http"
     8  	"runtime"
     9  	"strconv"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/docker/docker/daemon/logger"
    14  	"gotest.tools/v3/assert"
    15  )
    16  
    17  // Validate options
    18  func TestValidateLogOpt(t *testing.T) {
    19  	err := ValidateLogOpt(map[string]string{
    20  		splunkURLKey:                  "http://127.0.0.1",
    21  		splunkTokenKey:                "2160C7EF-2CE9-4307-A180-F852B99CF417",
    22  		splunkSourceKey:               "mysource",
    23  		splunkSourceTypeKey:           "mysourcetype",
    24  		splunkIndexKey:                "myindex",
    25  		splunkCAPathKey:               "/usr/cert.pem",
    26  		splunkCANameKey:               "ca_name",
    27  		splunkInsecureSkipVerifyKey:   "true",
    28  		splunkFormatKey:               "json",
    29  		splunkVerifyConnectionKey:     "true",
    30  		splunkGzipCompressionKey:      "true",
    31  		splunkGzipCompressionLevelKey: "1",
    32  		envKey:                        "a",
    33  		envRegexKey:                   "^foo",
    34  		labelsKey:                     "b",
    35  		tagKey:                        "c",
    36  	})
    37  	if err != nil {
    38  		t.Fatal(err)
    39  	}
    40  
    41  	err = ValidateLogOpt(map[string]string{
    42  		"not-supported-option": "a",
    43  	})
    44  	if err == nil {
    45  		t.Fatal("Expecting error on unsupported options")
    46  	}
    47  }
    48  
    49  // Driver require user to specify required options
    50  func TestNewMissedConfig(t *testing.T) {
    51  	info := logger.Info{
    52  		Config: map[string]string{},
    53  	}
    54  	_, err := New(info)
    55  	if err == nil {
    56  		t.Fatal("Logger driver should fail when no required parameters specified")
    57  	}
    58  }
    59  
    60  // Driver require user to specify splunk-url
    61  func TestNewMissedUrl(t *testing.T) {
    62  	info := logger.Info{
    63  		Config: map[string]string{
    64  			splunkTokenKey: "4642492F-D8BD-47F1-A005-0C08AE4657DF",
    65  		},
    66  	}
    67  	_, err := New(info)
    68  	if err.Error() != "splunk: splunk-url is expected" {
    69  		t.Fatal("Logger driver should fail when no required parameters specified")
    70  	}
    71  }
    72  
    73  // Driver require user to specify splunk-token
    74  func TestNewMissedToken(t *testing.T) {
    75  	info := logger.Info{
    76  		Config: map[string]string{
    77  			splunkURLKey: "http://127.0.0.1:8088",
    78  		},
    79  	}
    80  	_, err := New(info)
    81  	if err.Error() != "splunk: splunk-token is expected" {
    82  		t.Fatal("Logger driver should fail when no required parameters specified")
    83  	}
    84  }
    85  
    86  func TestNewWithProxy(t *testing.T) {
    87  	proxy := "http://proxy.testing:8888"
    88  	t.Setenv("HTTP_PROXY", proxy)
    89  
    90  	// must not be localhost
    91  	splunkURL := "http://example.com:12345"
    92  	logger, err := New(logger.Info{
    93  		Config: map[string]string{
    94  			splunkURLKey:              splunkURL,
    95  			splunkTokenKey:            "token",
    96  			splunkVerifyConnectionKey: "false",
    97  		},
    98  		ContainerID: "containeriid",
    99  	})
   100  	assert.NilError(t, err)
   101  	splunkLogger := logger.(*splunkLoggerInline)
   102  
   103  	proxyFunc := splunkLogger.transport.Proxy
   104  	assert.Assert(t, proxyFunc != nil)
   105  
   106  	req, err := http.NewRequest(http.MethodGet, splunkURL, nil)
   107  	assert.NilError(t, err)
   108  
   109  	proxyURL, err := proxyFunc(req)
   110  	assert.NilError(t, err)
   111  	assert.Assert(t, proxyURL != nil)
   112  	assert.Equal(t, proxy, proxyURL.String())
   113  }
   114  
   115  // Test default settings
   116  func TestDefault(t *testing.T) {
   117  	hec := NewHTTPEventCollectorMock(t)
   118  
   119  	go hec.Serve()
   120  
   121  	info := logger.Info{
   122  		Config: map[string]string{
   123  			splunkURLKey:   hec.URL(),
   124  			splunkTokenKey: hec.token,
   125  		},
   126  		ContainerID:        "containeriid",
   127  		ContainerName:      "container_name",
   128  		ContainerImageID:   "contaimageid",
   129  		ContainerImageName: "container_image_name",
   130  	}
   131  
   132  	hostname, err := info.Hostname()
   133  	if err != nil {
   134  		t.Fatal(err)
   135  	}
   136  
   137  	loggerDriver, err := New(info)
   138  	if err != nil {
   139  		t.Fatal(err)
   140  	}
   141  
   142  	if loggerDriver.Name() != driverName {
   143  		t.Fatal("Unexpected logger driver name")
   144  	}
   145  
   146  	if !hec.connectionVerified {
   147  		t.Fatal("By default connection should be verified")
   148  	}
   149  
   150  	splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerInline)
   151  	if !ok {
   152  		t.Fatal("Unexpected Splunk Logging Driver type")
   153  	}
   154  
   155  	if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" ||
   156  		splunkLoggerDriver.auth != "Splunk "+hec.token ||
   157  		splunkLoggerDriver.nullMessage.Host != hostname ||
   158  		splunkLoggerDriver.nullMessage.Source != "" ||
   159  		splunkLoggerDriver.nullMessage.SourceType != "" ||
   160  		splunkLoggerDriver.nullMessage.Index != "" ||
   161  		splunkLoggerDriver.gzipCompression ||
   162  		splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency ||
   163  		splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize ||
   164  		splunkLoggerDriver.bufferMaximum != defaultBufferMaximum ||
   165  		cap(splunkLoggerDriver.stream) != defaultStreamChannelSize {
   166  		t.Fatal("Found not default values setup in Splunk Logging Driver.")
   167  	}
   168  
   169  	message1Time := time.Now()
   170  	if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil {
   171  		t.Fatal(err)
   172  	}
   173  	message2Time := time.Now()
   174  	if err := loggerDriver.Log(&logger.Message{Line: []byte("notajson"), Source: "stdout", Timestamp: message2Time}); err != nil {
   175  		t.Fatal(err)
   176  	}
   177  
   178  	err = loggerDriver.Close()
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	if len(hec.messages) != 2 {
   184  		t.Fatal("Expected two messages")
   185  	}
   186  
   187  	if *hec.gzipEnabled {
   188  		t.Fatal("Gzip should not be used")
   189  	}
   190  
   191  	message1 := hec.messages[0]
   192  	if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) ||
   193  		message1.Host != hostname ||
   194  		message1.Source != "" ||
   195  		message1.SourceType != "" ||
   196  		message1.Index != "" {
   197  		t.Fatalf("Unexpected values of message 1 %v", message1)
   198  	}
   199  
   200  	if event, err := message1.EventAsMap(); err != nil {
   201  		t.Fatal(err)
   202  	} else {
   203  		if event["line"] != "{\"a\":\"b\"}" ||
   204  			event["source"] != "stdout" ||
   205  			event["tag"] != "containeriid" ||
   206  			len(event) != 3 {
   207  			t.Fatalf("Unexpected event in message %v", event)
   208  		}
   209  	}
   210  
   211  	message2 := hec.messages[1]
   212  	if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) ||
   213  		message2.Host != hostname ||
   214  		message2.Source != "" ||
   215  		message2.SourceType != "" ||
   216  		message2.Index != "" {
   217  		t.Fatalf("Unexpected values of message 1 %v", message2)
   218  	}
   219  
   220  	if event, err := message2.EventAsMap(); err != nil {
   221  		t.Fatal(err)
   222  	} else {
   223  		if event["line"] != "notajson" ||
   224  			event["source"] != "stdout" ||
   225  			event["tag"] != "containeriid" ||
   226  			len(event) != 3 {
   227  			t.Fatalf("Unexpected event in message %v", event)
   228  		}
   229  	}
   230  
   231  	err = hec.Close()
   232  	if err != nil {
   233  		t.Fatal(err)
   234  	}
   235  }
   236  
   237  // Verify inline format with a not default settings for most of options
   238  func TestInlineFormatWithNonDefaultOptions(t *testing.T) {
   239  	hec := NewHTTPEventCollectorMock(t)
   240  
   241  	go hec.Serve()
   242  
   243  	info := logger.Info{
   244  		Config: map[string]string{
   245  			splunkURLKey:             hec.URL(),
   246  			splunkTokenKey:           hec.token,
   247  			splunkSourceKey:          "mysource",
   248  			splunkSourceTypeKey:      "mysourcetype",
   249  			splunkIndexKey:           "myindex",
   250  			splunkFormatKey:          splunkFormatInline,
   251  			splunkGzipCompressionKey: "true",
   252  			tagKey:                   "{{.ImageName}}/{{.Name}}",
   253  			labelsKey:                "a",
   254  			envRegexKey:              "^foo",
   255  		},
   256  		ContainerID:        "containeriid",
   257  		ContainerName:      "/container_name",
   258  		ContainerImageID:   "contaimageid",
   259  		ContainerImageName: "container_image_name",
   260  		ContainerLabels: map[string]string{
   261  			"a": "b",
   262  		},
   263  		ContainerEnv: []string{"foo_finder=bar"},
   264  	}
   265  
   266  	hostname, err := info.Hostname()
   267  	if err != nil {
   268  		t.Fatal(err)
   269  	}
   270  
   271  	loggerDriver, err := New(info)
   272  	if err != nil {
   273  		t.Fatal(err)
   274  	}
   275  
   276  	if !hec.connectionVerified {
   277  		t.Fatal("By default connection should be verified")
   278  	}
   279  
   280  	splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerInline)
   281  	if !ok {
   282  		t.Fatal("Unexpected Splunk Logging Driver type")
   283  	}
   284  
   285  	if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" ||
   286  		splunkLoggerDriver.auth != "Splunk "+hec.token ||
   287  		splunkLoggerDriver.nullMessage.Host != hostname ||
   288  		splunkLoggerDriver.nullMessage.Source != "mysource" ||
   289  		splunkLoggerDriver.nullMessage.SourceType != "mysourcetype" ||
   290  		splunkLoggerDriver.nullMessage.Index != "myindex" ||
   291  		!splunkLoggerDriver.gzipCompression ||
   292  		splunkLoggerDriver.gzipCompressionLevel != gzip.DefaultCompression ||
   293  		splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency ||
   294  		splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize ||
   295  		splunkLoggerDriver.bufferMaximum != defaultBufferMaximum ||
   296  		cap(splunkLoggerDriver.stream) != defaultStreamChannelSize {
   297  		t.Fatal("Values do not match configuration.")
   298  	}
   299  
   300  	messageTime := time.Now()
   301  	if err := loggerDriver.Log(&logger.Message{Line: []byte("1"), Source: "stdout", Timestamp: messageTime}); err != nil {
   302  		t.Fatal(err)
   303  	}
   304  
   305  	err = loggerDriver.Close()
   306  	if err != nil {
   307  		t.Fatal(err)
   308  	}
   309  
   310  	if len(hec.messages) != 1 {
   311  		t.Fatal("Expected one message")
   312  	}
   313  
   314  	if !*hec.gzipEnabled {
   315  		t.Fatal("Gzip should be used")
   316  	}
   317  
   318  	message := hec.messages[0]
   319  	if message.Time != fmt.Sprintf("%f", float64(messageTime.UnixNano())/float64(time.Second)) ||
   320  		message.Host != hostname ||
   321  		message.Source != "mysource" ||
   322  		message.SourceType != "mysourcetype" ||
   323  		message.Index != "myindex" {
   324  		t.Fatalf("Unexpected values of message %v", message)
   325  	}
   326  
   327  	if event, err := message.EventAsMap(); err != nil {
   328  		t.Fatal(err)
   329  	} else {
   330  		if event["line"] != "1" ||
   331  			event["source"] != "stdout" ||
   332  			event["tag"] != "container_image_name/container_name" ||
   333  			event["attrs"].(map[string]interface{})["a"] != "b" ||
   334  			event["attrs"].(map[string]interface{})["foo_finder"] != "bar" ||
   335  			len(event) != 4 {
   336  			t.Fatalf("Unexpected event in message %v", event)
   337  		}
   338  	}
   339  
   340  	err = hec.Close()
   341  	if err != nil {
   342  		t.Fatal(err)
   343  	}
   344  }
   345  
   346  // Verify JSON format
   347  func TestJsonFormat(t *testing.T) {
   348  	hec := NewHTTPEventCollectorMock(t)
   349  
   350  	go hec.Serve()
   351  
   352  	info := logger.Info{
   353  		Config: map[string]string{
   354  			splunkURLKey:                  hec.URL(),
   355  			splunkTokenKey:                hec.token,
   356  			splunkFormatKey:               splunkFormatJSON,
   357  			splunkGzipCompressionKey:      "true",
   358  			splunkGzipCompressionLevelKey: "1",
   359  		},
   360  		ContainerID:        "containeriid",
   361  		ContainerName:      "/container_name",
   362  		ContainerImageID:   "contaimageid",
   363  		ContainerImageName: "container_image_name",
   364  	}
   365  
   366  	hostname, err := info.Hostname()
   367  	if err != nil {
   368  		t.Fatal(err)
   369  	}
   370  
   371  	loggerDriver, err := New(info)
   372  	if err != nil {
   373  		t.Fatal(err)
   374  	}
   375  
   376  	if !hec.connectionVerified {
   377  		t.Fatal("By default connection should be verified")
   378  	}
   379  
   380  	splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerJSON)
   381  	if !ok {
   382  		t.Fatal("Unexpected Splunk Logging Driver type")
   383  	}
   384  
   385  	if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" ||
   386  		splunkLoggerDriver.auth != "Splunk "+hec.token ||
   387  		splunkLoggerDriver.nullMessage.Host != hostname ||
   388  		splunkLoggerDriver.nullMessage.Source != "" ||
   389  		splunkLoggerDriver.nullMessage.SourceType != "" ||
   390  		splunkLoggerDriver.nullMessage.Index != "" ||
   391  		!splunkLoggerDriver.gzipCompression ||
   392  		splunkLoggerDriver.gzipCompressionLevel != gzip.BestSpeed ||
   393  		splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency ||
   394  		splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize ||
   395  		splunkLoggerDriver.bufferMaximum != defaultBufferMaximum ||
   396  		cap(splunkLoggerDriver.stream) != defaultStreamChannelSize {
   397  		t.Fatal("Values do not match configuration.")
   398  	}
   399  
   400  	message1Time := time.Now()
   401  	if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil {
   402  		t.Fatal(err)
   403  	}
   404  	message2Time := time.Now()
   405  	if err := loggerDriver.Log(&logger.Message{Line: []byte("notjson"), Source: "stdout", Timestamp: message2Time}); err != nil {
   406  		t.Fatal(err)
   407  	}
   408  
   409  	err = loggerDriver.Close()
   410  	if err != nil {
   411  		t.Fatal(err)
   412  	}
   413  
   414  	if len(hec.messages) != 2 {
   415  		t.Fatal("Expected two messages")
   416  	}
   417  
   418  	message1 := hec.messages[0]
   419  	if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) ||
   420  		message1.Host != hostname ||
   421  		message1.Source != "" ||
   422  		message1.SourceType != "" ||
   423  		message1.Index != "" {
   424  		t.Fatalf("Unexpected values of message 1 %v", message1)
   425  	}
   426  
   427  	if event, err := message1.EventAsMap(); err != nil {
   428  		t.Fatal(err)
   429  	} else {
   430  		if event["line"].(map[string]interface{})["a"] != "b" ||
   431  			event["source"] != "stdout" ||
   432  			event["tag"] != "containeriid" ||
   433  			len(event) != 3 {
   434  			t.Fatalf("Unexpected event in message 1 %v", event)
   435  		}
   436  	}
   437  
   438  	message2 := hec.messages[1]
   439  	if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) ||
   440  		message2.Host != hostname ||
   441  		message2.Source != "" ||
   442  		message2.SourceType != "" ||
   443  		message2.Index != "" {
   444  		t.Fatalf("Unexpected values of message 2 %v", message2)
   445  	}
   446  
   447  	// If message cannot be parsed as JSON - it should be sent as a line
   448  	if event, err := message2.EventAsMap(); err != nil {
   449  		t.Fatal(err)
   450  	} else {
   451  		if event["line"] != "notjson" ||
   452  			event["source"] != "stdout" ||
   453  			event["tag"] != "containeriid" ||
   454  			len(event) != 3 {
   455  			t.Fatalf("Unexpected event in message 2 %v", event)
   456  		}
   457  	}
   458  
   459  	err = hec.Close()
   460  	if err != nil {
   461  		t.Fatal(err)
   462  	}
   463  }
   464  
   465  // Verify raw format
   466  func TestRawFormat(t *testing.T) {
   467  	hec := NewHTTPEventCollectorMock(t)
   468  
   469  	go hec.Serve()
   470  
   471  	info := logger.Info{
   472  		Config: map[string]string{
   473  			splunkURLKey:    hec.URL(),
   474  			splunkTokenKey:  hec.token,
   475  			splunkFormatKey: splunkFormatRaw,
   476  		},
   477  		ContainerID:        "containeriid",
   478  		ContainerName:      "/container_name",
   479  		ContainerImageID:   "contaimageid",
   480  		ContainerImageName: "container_image_name",
   481  	}
   482  
   483  	hostname, err := info.Hostname()
   484  	assert.NilError(t, err)
   485  
   486  	loggerDriver, err := New(info)
   487  	assert.NilError(t, err)
   488  
   489  	if !hec.connectionVerified {
   490  		t.Fatal("By default connection should be verified")
   491  	}
   492  
   493  	splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerRaw)
   494  	if !ok {
   495  		t.Fatal("Unexpected Splunk Logging Driver type")
   496  	}
   497  
   498  	if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" ||
   499  		splunkLoggerDriver.auth != "Splunk "+hec.token ||
   500  		splunkLoggerDriver.nullMessage.Host != hostname ||
   501  		splunkLoggerDriver.nullMessage.Source != "" ||
   502  		splunkLoggerDriver.nullMessage.SourceType != "" ||
   503  		splunkLoggerDriver.nullMessage.Index != "" ||
   504  		splunkLoggerDriver.gzipCompression ||
   505  		splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency ||
   506  		splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize ||
   507  		splunkLoggerDriver.bufferMaximum != defaultBufferMaximum ||
   508  		cap(splunkLoggerDriver.stream) != defaultStreamChannelSize ||
   509  		string(splunkLoggerDriver.prefix) != "containeriid " {
   510  		t.Fatal("Values do not match configuration.")
   511  	}
   512  
   513  	message1Time := time.Now()
   514  	if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil {
   515  		t.Fatal(err)
   516  	}
   517  	message2Time := time.Now()
   518  	if err := loggerDriver.Log(&logger.Message{Line: []byte("notjson"), Source: "stdout", Timestamp: message2Time}); err != nil {
   519  		t.Fatal(err)
   520  	}
   521  
   522  	err = loggerDriver.Close()
   523  	if err != nil {
   524  		t.Fatal(err)
   525  	}
   526  
   527  	if len(hec.messages) != 2 {
   528  		t.Fatal("Expected two messages")
   529  	}
   530  
   531  	message1 := hec.messages[0]
   532  	if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) ||
   533  		message1.Host != hostname ||
   534  		message1.Source != "" ||
   535  		message1.SourceType != "" ||
   536  		message1.Index != "" {
   537  		t.Fatalf("Unexpected values of message 1 %v", message1)
   538  	}
   539  
   540  	if event, err := message1.EventAsString(); err != nil {
   541  		t.Fatal(err)
   542  	} else {
   543  		if event != "containeriid {\"a\":\"b\"}" {
   544  			t.Fatalf("Unexpected event in message 1 %v", event)
   545  		}
   546  	}
   547  
   548  	message2 := hec.messages[1]
   549  	if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) ||
   550  		message2.Host != hostname ||
   551  		message2.Source != "" ||
   552  		message2.SourceType != "" ||
   553  		message2.Index != "" {
   554  		t.Fatalf("Unexpected values of message 2 %v", message2)
   555  	}
   556  
   557  	if event, err := message2.EventAsString(); err != nil {
   558  		t.Fatal(err)
   559  	} else {
   560  		if event != "containeriid notjson" {
   561  			t.Fatalf("Unexpected event in message 1 %v", event)
   562  		}
   563  	}
   564  
   565  	err = hec.Close()
   566  	if err != nil {
   567  		t.Fatal(err)
   568  	}
   569  }
   570  
   571  // Verify raw format with labels
   572  func TestRawFormatWithLabels(t *testing.T) {
   573  	hec := NewHTTPEventCollectorMock(t)
   574  
   575  	go hec.Serve()
   576  
   577  	info := logger.Info{
   578  		Config: map[string]string{
   579  			splunkURLKey:    hec.URL(),
   580  			splunkTokenKey:  hec.token,
   581  			splunkFormatKey: splunkFormatRaw,
   582  			labelsKey:       "a",
   583  		},
   584  		ContainerID:        "containeriid",
   585  		ContainerName:      "/container_name",
   586  		ContainerImageID:   "contaimageid",
   587  		ContainerImageName: "container_image_name",
   588  		ContainerLabels: map[string]string{
   589  			"a": "b",
   590  		},
   591  	}
   592  
   593  	hostname, err := info.Hostname()
   594  	if err != nil {
   595  		t.Fatal(err)
   596  	}
   597  
   598  	loggerDriver, err := New(info)
   599  	if err != nil {
   600  		t.Fatal(err)
   601  	}
   602  
   603  	if !hec.connectionVerified {
   604  		t.Fatal("By default connection should be verified")
   605  	}
   606  
   607  	splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerRaw)
   608  	if !ok {
   609  		t.Fatal("Unexpected Splunk Logging Driver type")
   610  	}
   611  
   612  	if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" ||
   613  		splunkLoggerDriver.auth != "Splunk "+hec.token ||
   614  		splunkLoggerDriver.nullMessage.Host != hostname ||
   615  		splunkLoggerDriver.nullMessage.Source != "" ||
   616  		splunkLoggerDriver.nullMessage.SourceType != "" ||
   617  		splunkLoggerDriver.nullMessage.Index != "" ||
   618  		splunkLoggerDriver.gzipCompression ||
   619  		splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency ||
   620  		splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize ||
   621  		splunkLoggerDriver.bufferMaximum != defaultBufferMaximum ||
   622  		cap(splunkLoggerDriver.stream) != defaultStreamChannelSize ||
   623  		string(splunkLoggerDriver.prefix) != "containeriid a=b " {
   624  		t.Fatal("Values do not match configuration.")
   625  	}
   626  
   627  	message1Time := time.Now()
   628  	if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil {
   629  		t.Fatal(err)
   630  	}
   631  	message2Time := time.Now()
   632  	if err := loggerDriver.Log(&logger.Message{Line: []byte("notjson"), Source: "stdout", Timestamp: message2Time}); err != nil {
   633  		t.Fatal(err)
   634  	}
   635  
   636  	err = loggerDriver.Close()
   637  	if err != nil {
   638  		t.Fatal(err)
   639  	}
   640  
   641  	if len(hec.messages) != 2 {
   642  		t.Fatal("Expected two messages")
   643  	}
   644  
   645  	message1 := hec.messages[0]
   646  	if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) ||
   647  		message1.Host != hostname ||
   648  		message1.Source != "" ||
   649  		message1.SourceType != "" ||
   650  		message1.Index != "" {
   651  		t.Fatalf("Unexpected values of message 1 %v", message1)
   652  	}
   653  
   654  	if event, err := message1.EventAsString(); err != nil {
   655  		t.Fatal(err)
   656  	} else {
   657  		if event != "containeriid a=b {\"a\":\"b\"}" {
   658  			t.Fatalf("Unexpected event in message 1 %v", event)
   659  		}
   660  	}
   661  
   662  	message2 := hec.messages[1]
   663  	if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) ||
   664  		message2.Host != hostname ||
   665  		message2.Source != "" ||
   666  		message2.SourceType != "" ||
   667  		message2.Index != "" {
   668  		t.Fatalf("Unexpected values of message 2 %v", message2)
   669  	}
   670  
   671  	if event, err := message2.EventAsString(); err != nil {
   672  		t.Fatal(err)
   673  	} else {
   674  		if event != "containeriid a=b notjson" {
   675  			t.Fatalf("Unexpected event in message 2 %v", event)
   676  		}
   677  	}
   678  
   679  	err = hec.Close()
   680  	if err != nil {
   681  		t.Fatal(err)
   682  	}
   683  }
   684  
   685  // Verify that Splunk Logging Driver can accept tag="" which will allow to send raw messages
   686  // in the same way we get them in stdout/stderr
   687  func TestRawFormatWithoutTag(t *testing.T) {
   688  	hec := NewHTTPEventCollectorMock(t)
   689  
   690  	go hec.Serve()
   691  
   692  	info := logger.Info{
   693  		Config: map[string]string{
   694  			splunkURLKey:    hec.URL(),
   695  			splunkTokenKey:  hec.token,
   696  			splunkFormatKey: splunkFormatRaw,
   697  			tagKey:          "",
   698  		},
   699  		ContainerID:        "containeriid",
   700  		ContainerName:      "/container_name",
   701  		ContainerImageID:   "contaimageid",
   702  		ContainerImageName: "container_image_name",
   703  	}
   704  
   705  	hostname, err := info.Hostname()
   706  	if err != nil {
   707  		t.Fatal(err)
   708  	}
   709  
   710  	loggerDriver, err := New(info)
   711  	if err != nil {
   712  		t.Fatal(err)
   713  	}
   714  
   715  	if !hec.connectionVerified {
   716  		t.Fatal("By default connection should be verified")
   717  	}
   718  
   719  	splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerRaw)
   720  	if !ok {
   721  		t.Fatal("Unexpected Splunk Logging Driver type")
   722  	}
   723  
   724  	if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" ||
   725  		splunkLoggerDriver.auth != "Splunk "+hec.token ||
   726  		splunkLoggerDriver.nullMessage.Host != hostname ||
   727  		splunkLoggerDriver.nullMessage.Source != "" ||
   728  		splunkLoggerDriver.nullMessage.SourceType != "" ||
   729  		splunkLoggerDriver.nullMessage.Index != "" ||
   730  		splunkLoggerDriver.gzipCompression ||
   731  		splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency ||
   732  		splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize ||
   733  		splunkLoggerDriver.bufferMaximum != defaultBufferMaximum ||
   734  		cap(splunkLoggerDriver.stream) != defaultStreamChannelSize ||
   735  		string(splunkLoggerDriver.prefix) != "" {
   736  		t.Log(string(splunkLoggerDriver.prefix) + "a")
   737  		t.Fatal("Values do not match configuration.")
   738  	}
   739  
   740  	message1Time := time.Now()
   741  	if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil {
   742  		t.Fatal(err)
   743  	}
   744  	message2Time := time.Now()
   745  	if err := loggerDriver.Log(&logger.Message{Line: []byte("notjson"), Source: "stdout", Timestamp: message2Time}); err != nil {
   746  		t.Fatal(err)
   747  	}
   748  	message3Time := time.Now()
   749  	if err := loggerDriver.Log(&logger.Message{Line: []byte(" "), Source: "stdout", Timestamp: message3Time}); err != nil {
   750  		t.Fatal(err)
   751  	}
   752  
   753  	err = loggerDriver.Close()
   754  	if err != nil {
   755  		t.Fatal(err)
   756  	}
   757  
   758  	// message3 would have an empty or whitespace only string in the "event" field
   759  	// both of which are not acceptable to HEC
   760  	// thus here we must expect 2 messages, not 3
   761  	if len(hec.messages) != 2 {
   762  		t.Fatal("Expected two messages")
   763  	}
   764  
   765  	message1 := hec.messages[0]
   766  	if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) ||
   767  		message1.Host != hostname ||
   768  		message1.Source != "" ||
   769  		message1.SourceType != "" ||
   770  		message1.Index != "" {
   771  		t.Fatalf("Unexpected values of message 1 %v", message1)
   772  	}
   773  
   774  	if event, err := message1.EventAsString(); err != nil {
   775  		t.Fatal(err)
   776  	} else {
   777  		if event != "{\"a\":\"b\"}" {
   778  			t.Fatalf("Unexpected event in message 1 %v", event)
   779  		}
   780  	}
   781  
   782  	message2 := hec.messages[1]
   783  	if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) ||
   784  		message2.Host != hostname ||
   785  		message2.Source != "" ||
   786  		message2.SourceType != "" ||
   787  		message2.Index != "" {
   788  		t.Fatalf("Unexpected values of message 2 %v", message2)
   789  	}
   790  
   791  	if event, err := message2.EventAsString(); err != nil {
   792  		t.Fatal(err)
   793  	} else {
   794  		if event != "notjson" {
   795  			t.Fatalf("Unexpected event in message 2 %v", event)
   796  		}
   797  	}
   798  
   799  	err = hec.Close()
   800  	if err != nil {
   801  		t.Fatal(err)
   802  	}
   803  }
   804  
   805  // Verify that we will send messages in batches with default batching parameters,
   806  // but change frequency to be sure that numOfRequests will match expected 17 requests
   807  func TestBatching(t *testing.T) {
   808  	t.Setenv(envVarPostMessagesFrequency, "10h")
   809  
   810  	hec := NewHTTPEventCollectorMock(t)
   811  
   812  	go hec.Serve()
   813  
   814  	info := logger.Info{
   815  		Config: map[string]string{
   816  			splunkURLKey:   hec.URL(),
   817  			splunkTokenKey: hec.token,
   818  		},
   819  		ContainerID:        "containeriid",
   820  		ContainerName:      "/container_name",
   821  		ContainerImageID:   "contaimageid",
   822  		ContainerImageName: "container_image_name",
   823  	}
   824  
   825  	loggerDriver, err := New(info)
   826  	if err != nil {
   827  		t.Fatal(err)
   828  	}
   829  
   830  	for i := 0; i < defaultStreamChannelSize*4; i++ {
   831  		if err := loggerDriver.Log(&logger.Message{Line: []byte(strconv.Itoa(i)), Source: "stdout", Timestamp: time.Now()}); err != nil {
   832  			t.Fatal(err)
   833  		}
   834  	}
   835  
   836  	err = loggerDriver.Close()
   837  	if err != nil {
   838  		t.Fatal(err)
   839  	}
   840  
   841  	if len(hec.messages) != defaultStreamChannelSize*4 {
   842  		t.Fatal("Not all messages delivered")
   843  	}
   844  
   845  	for i, message := range hec.messages {
   846  		if event, err := message.EventAsMap(); err != nil {
   847  			t.Fatal(err)
   848  		} else {
   849  			if event["line"] != strconv.Itoa(i) {
   850  				t.Fatalf("Unexpected event in message %v", event)
   851  			}
   852  		}
   853  	}
   854  
   855  	// 1 to verify connection and 16 batches
   856  	if hec.numOfRequests != 17 {
   857  		t.Fatalf("Unexpected number of requests %d", hec.numOfRequests)
   858  	}
   859  
   860  	err = hec.Close()
   861  	if err != nil {
   862  		t.Fatal(err)
   863  	}
   864  }
   865  
   866  // Verify that test is using time to fire events not rare than specified frequency
   867  func TestFrequency(t *testing.T) {
   868  	t.Setenv(envVarPostMessagesFrequency, "5ms")
   869  
   870  	hec := NewHTTPEventCollectorMock(t)
   871  
   872  	go hec.Serve()
   873  
   874  	info := logger.Info{
   875  		Config: map[string]string{
   876  			splunkURLKey:   hec.URL(),
   877  			splunkTokenKey: hec.token,
   878  		},
   879  		ContainerID:        "containeriid",
   880  		ContainerName:      "/container_name",
   881  		ContainerImageID:   "contaimageid",
   882  		ContainerImageName: "container_image_name",
   883  	}
   884  
   885  	loggerDriver, err := New(info)
   886  	if err != nil {
   887  		t.Fatal(err)
   888  	}
   889  
   890  	for i := 0; i < 10; i++ {
   891  		if err := loggerDriver.Log(&logger.Message{Line: []byte(strconv.Itoa(i)), Source: "stdout", Timestamp: time.Now()}); err != nil {
   892  			t.Fatal(err)
   893  		}
   894  		time.Sleep(15 * time.Millisecond)
   895  	}
   896  
   897  	err = loggerDriver.Close()
   898  	if err != nil {
   899  		t.Fatal(err)
   900  	}
   901  
   902  	if len(hec.messages) != 10 {
   903  		t.Fatal("Not all messages delivered")
   904  	}
   905  
   906  	for i, message := range hec.messages {
   907  		if event, err := message.EventAsMap(); err != nil {
   908  			t.Fatal(err)
   909  		} else {
   910  			if event["line"] != strconv.Itoa(i) {
   911  				t.Fatalf("Unexpected event in message %v", event)
   912  			}
   913  		}
   914  	}
   915  
   916  	// 1 to verify connection and 10 to verify that we have sent messages with required frequency,
   917  	// but because frequency is too small (to keep test quick), instead of 11, use 9 if context switches will be slow
   918  	expectedRequests := 9
   919  	if runtime.GOOS == "windows" {
   920  		// sometimes in Windows, this test fails with number of requests showing 8. So be more conservative.
   921  		expectedRequests = 7
   922  	}
   923  	if hec.numOfRequests < expectedRequests {
   924  		t.Fatalf("Unexpected number of requests %d", hec.numOfRequests)
   925  	}
   926  
   927  	err = hec.Close()
   928  	if err != nil {
   929  		t.Fatal(err)
   930  	}
   931  }
   932  
   933  // Simulate behavior similar to first version of Splunk Logging Driver, when we were sending one message
   934  // per request
   935  func TestOneMessagePerRequest(t *testing.T) {
   936  	t.Setenv(envVarPostMessagesFrequency, "10h")
   937  	t.Setenv(envVarPostMessagesBatchSize, "1")
   938  	t.Setenv(envVarBufferMaximum, "1")
   939  	t.Setenv(envVarStreamChannelSize, "0")
   940  
   941  	hec := NewHTTPEventCollectorMock(t)
   942  
   943  	go hec.Serve()
   944  
   945  	info := logger.Info{
   946  		Config: map[string]string{
   947  			splunkURLKey:   hec.URL(),
   948  			splunkTokenKey: hec.token,
   949  		},
   950  		ContainerID:        "containeriid",
   951  		ContainerName:      "/container_name",
   952  		ContainerImageID:   "contaimageid",
   953  		ContainerImageName: "container_image_name",
   954  	}
   955  
   956  	loggerDriver, err := New(info)
   957  	if err != nil {
   958  		t.Fatal(err)
   959  	}
   960  
   961  	for i := 0; i < 10; i++ {
   962  		if err := loggerDriver.Log(&logger.Message{Line: []byte(strconv.Itoa(i)), Source: "stdout", Timestamp: time.Now()}); err != nil {
   963  			t.Fatal(err)
   964  		}
   965  	}
   966  
   967  	err = loggerDriver.Close()
   968  	if err != nil {
   969  		t.Fatal(err)
   970  	}
   971  
   972  	if len(hec.messages) != 10 {
   973  		t.Fatal("Not all messages delivered")
   974  	}
   975  
   976  	for i, message := range hec.messages {
   977  		if event, err := message.EventAsMap(); err != nil {
   978  			t.Fatal(err)
   979  		} else {
   980  			if event["line"] != strconv.Itoa(i) {
   981  				t.Fatalf("Unexpected event in message %v", event)
   982  			}
   983  		}
   984  	}
   985  
   986  	// 1 to verify connection and 10 messages
   987  	if hec.numOfRequests != 11 {
   988  		t.Fatalf("Unexpected number of requests %d", hec.numOfRequests)
   989  	}
   990  
   991  	err = hec.Close()
   992  	if err != nil {
   993  		t.Fatal(err)
   994  	}
   995  }
   996  
   997  // Driver should not be created when HEC is unresponsive
   998  func TestVerify(t *testing.T) {
   999  	hec := NewHTTPEventCollectorMock(t)
  1000  	hec.simulateServerError = true
  1001  	go hec.Serve()
  1002  
  1003  	info := logger.Info{
  1004  		Config: map[string]string{
  1005  			splunkURLKey:   hec.URL(),
  1006  			splunkTokenKey: hec.token,
  1007  		},
  1008  		ContainerID:        "containeriid",
  1009  		ContainerName:      "/container_name",
  1010  		ContainerImageID:   "contaimageid",
  1011  		ContainerImageName: "container_image_name",
  1012  	}
  1013  
  1014  	_, err := New(info)
  1015  	if err == nil {
  1016  		t.Fatal("Expecting driver to fail, when server is unresponsive")
  1017  	}
  1018  
  1019  	err = hec.Close()
  1020  	if err != nil {
  1021  		t.Fatal(err)
  1022  	}
  1023  }
  1024  
  1025  // Verify that user can specify to skip verification that Splunk HEC is working.
  1026  // Also in this test we verify retry logic.
  1027  func TestSkipVerify(t *testing.T) {
  1028  	hec := NewHTTPEventCollectorMock(t)
  1029  	hec.simulateServerError = true
  1030  	go hec.Serve()
  1031  
  1032  	info := logger.Info{
  1033  		Config: map[string]string{
  1034  			splunkURLKey:              hec.URL(),
  1035  			splunkTokenKey:            hec.token,
  1036  			splunkVerifyConnectionKey: "false",
  1037  		},
  1038  		ContainerID:        "containeriid",
  1039  		ContainerName:      "/container_name",
  1040  		ContainerImageID:   "contaimageid",
  1041  		ContainerImageName: "container_image_name",
  1042  	}
  1043  
  1044  	loggerDriver, err := New(info)
  1045  	if err != nil {
  1046  		t.Fatal(err)
  1047  	}
  1048  
  1049  	if hec.connectionVerified {
  1050  		t.Fatal("Connection should not be verified")
  1051  	}
  1052  
  1053  	for i := 0; i < defaultStreamChannelSize*2; i++ {
  1054  		if err := loggerDriver.Log(&logger.Message{Line: []byte(strconv.Itoa(i)), Source: "stdout", Timestamp: time.Now()}); err != nil {
  1055  			t.Fatal(err)
  1056  		}
  1057  	}
  1058  
  1059  	if len(hec.messages) != 0 {
  1060  		t.Fatal("No messages should be accepted at this point")
  1061  	}
  1062  
  1063  	hec.simulateErr(false)
  1064  
  1065  	for i := defaultStreamChannelSize * 2; i < defaultStreamChannelSize*4; i++ {
  1066  		if err := loggerDriver.Log(&logger.Message{Line: []byte(strconv.Itoa(i)), Source: "stdout", Timestamp: time.Now()}); err != nil {
  1067  			t.Fatal(err)
  1068  		}
  1069  	}
  1070  
  1071  	err = loggerDriver.Close()
  1072  	if err != nil {
  1073  		t.Fatal(err)
  1074  	}
  1075  
  1076  	if len(hec.messages) != defaultStreamChannelSize*4 {
  1077  		t.Fatal("Not all messages delivered")
  1078  	}
  1079  
  1080  	for i, message := range hec.messages {
  1081  		if event, err := message.EventAsMap(); err != nil {
  1082  			t.Fatal(err)
  1083  		} else {
  1084  			if event["line"] != strconv.Itoa(i) {
  1085  				t.Fatalf("Unexpected event in message %v", event)
  1086  			}
  1087  		}
  1088  	}
  1089  
  1090  	err = hec.Close()
  1091  	if err != nil {
  1092  		t.Fatal(err)
  1093  	}
  1094  }
  1095  
  1096  // Verify logic for when we filled whole buffer
  1097  func TestBufferMaximum(t *testing.T) {
  1098  	t.Setenv(envVarPostMessagesBatchSize, "2")
  1099  	t.Setenv(envVarBufferMaximum, "10")
  1100  	t.Setenv(envVarStreamChannelSize, "0")
  1101  
  1102  	hec := NewHTTPEventCollectorMock(t)
  1103  	hec.simulateErr(true)
  1104  	go hec.Serve()
  1105  
  1106  	info := logger.Info{
  1107  		Config: map[string]string{
  1108  			splunkURLKey:              hec.URL(),
  1109  			splunkTokenKey:            hec.token,
  1110  			splunkVerifyConnectionKey: "false",
  1111  		},
  1112  		ContainerID:        "containeriid",
  1113  		ContainerName:      "/container_name",
  1114  		ContainerImageID:   "contaimageid",
  1115  		ContainerImageName: "container_image_name",
  1116  	}
  1117  
  1118  	loggerDriver, err := New(info)
  1119  	if err != nil {
  1120  		t.Fatal(err)
  1121  	}
  1122  
  1123  	if hec.connectionVerified {
  1124  		t.Fatal("Connection should not be verified")
  1125  	}
  1126  
  1127  	for i := 0; i < 11; i++ {
  1128  		if err := loggerDriver.Log(&logger.Message{Line: []byte(strconv.Itoa(i)), Source: "stdout", Timestamp: time.Now()}); err != nil {
  1129  			t.Fatal(err)
  1130  		}
  1131  	}
  1132  
  1133  	if len(hec.messages) != 0 {
  1134  		t.Fatal("No messages should be accepted at this point")
  1135  	}
  1136  
  1137  	hec.simulateServerError = false
  1138  
  1139  	err = loggerDriver.Close()
  1140  	if err != nil {
  1141  		t.Fatal(err)
  1142  	}
  1143  
  1144  	if len(hec.messages) != 9 {
  1145  		t.Fatalf("Expected # of messages %d, got %d", 9, len(hec.messages))
  1146  	}
  1147  
  1148  	// First 1000 messages are written to daemon log when buffer was full
  1149  	for i, message := range hec.messages {
  1150  		if event, err := message.EventAsMap(); err != nil {
  1151  			t.Fatal(err)
  1152  		} else {
  1153  			if event["line"] != fmt.Sprintf("%d", i+2) {
  1154  				t.Fatalf("Unexpected event in message %v", event)
  1155  			}
  1156  		}
  1157  	}
  1158  
  1159  	err = hec.Close()
  1160  	if err != nil {
  1161  		t.Fatal(err)
  1162  	}
  1163  }
  1164  
  1165  // Verify that we are not blocking close when HEC is down for the whole time
  1166  func TestServerAlwaysDown(t *testing.T) {
  1167  	t.Setenv(envVarPostMessagesBatchSize, "2")
  1168  	t.Setenv(envVarBufferMaximum, "4")
  1169  	t.Setenv(envVarStreamChannelSize, "0")
  1170  
  1171  	hec := NewHTTPEventCollectorMock(t)
  1172  	hec.simulateServerError = true
  1173  	go hec.Serve()
  1174  
  1175  	info := logger.Info{
  1176  		Config: map[string]string{
  1177  			splunkURLKey:              hec.URL(),
  1178  			splunkTokenKey:            hec.token,
  1179  			splunkVerifyConnectionKey: "false",
  1180  		},
  1181  		ContainerID:        "containeriid",
  1182  		ContainerName:      "/container_name",
  1183  		ContainerImageID:   "contaimageid",
  1184  		ContainerImageName: "container_image_name",
  1185  	}
  1186  
  1187  	loggerDriver, err := New(info)
  1188  	if err != nil {
  1189  		t.Fatal(err)
  1190  	}
  1191  
  1192  	if hec.connectionVerified {
  1193  		t.Fatal("Connection should not be verified")
  1194  	}
  1195  
  1196  	for i := 0; i < 5; i++ {
  1197  		if err := loggerDriver.Log(&logger.Message{Line: []byte(strconv.Itoa(i)), Source: "stdout", Timestamp: time.Now()}); err != nil {
  1198  			t.Fatal(err)
  1199  		}
  1200  	}
  1201  
  1202  	err = loggerDriver.Close()
  1203  	if err != nil {
  1204  		t.Fatal(err)
  1205  	}
  1206  
  1207  	if len(hec.messages) != 0 {
  1208  		t.Fatal("No messages should be sent")
  1209  	}
  1210  
  1211  	err = hec.Close()
  1212  	if err != nil {
  1213  		t.Fatal(err)
  1214  	}
  1215  }
  1216  
  1217  // Cannot send messages after we close driver
  1218  func TestCannotSendAfterClose(t *testing.T) {
  1219  	hec := NewHTTPEventCollectorMock(t)
  1220  	go hec.Serve()
  1221  
  1222  	info := logger.Info{
  1223  		Config: map[string]string{
  1224  			splunkURLKey:   hec.URL(),
  1225  			splunkTokenKey: hec.token,
  1226  		},
  1227  		ContainerID:        "containeriid",
  1228  		ContainerName:      "/container_name",
  1229  		ContainerImageID:   "contaimageid",
  1230  		ContainerImageName: "container_image_name",
  1231  	}
  1232  
  1233  	loggerDriver, err := New(info)
  1234  	if err != nil {
  1235  		t.Fatal(err)
  1236  	}
  1237  
  1238  	if err := loggerDriver.Log(&logger.Message{Line: []byte("message1"), Source: "stdout", Timestamp: time.Now()}); err != nil {
  1239  		t.Fatal(err)
  1240  	}
  1241  
  1242  	err = loggerDriver.Close()
  1243  	if err != nil {
  1244  		t.Fatal(err)
  1245  	}
  1246  
  1247  	if err := loggerDriver.Log(&logger.Message{Line: []byte("message2"), Source: "stdout", Timestamp: time.Now()}); err == nil {
  1248  		t.Fatal("Driver should not allow to send messages after close")
  1249  	}
  1250  
  1251  	if len(hec.messages) != 1 {
  1252  		t.Fatal("Only one message should be sent")
  1253  	}
  1254  
  1255  	message := hec.messages[0]
  1256  	if event, err := message.EventAsMap(); err != nil {
  1257  		t.Fatal(err)
  1258  	} else {
  1259  		if event["line"] != "message1" {
  1260  			t.Fatalf("Unexpected event in message %v", event)
  1261  		}
  1262  	}
  1263  
  1264  	err = hec.Close()
  1265  	if err != nil {
  1266  		t.Fatal(err)
  1267  	}
  1268  }
  1269  
  1270  func TestDeadlockOnBlockedEndpoint(t *testing.T) {
  1271  	hec := NewHTTPEventCollectorMock(t)
  1272  	go hec.Serve()
  1273  	info := logger.Info{
  1274  		Config: map[string]string{
  1275  			splunkURLKey:   hec.URL(),
  1276  			splunkTokenKey: hec.token,
  1277  		},
  1278  		ContainerID:        "containeriid",
  1279  		ContainerName:      "/container_name",
  1280  		ContainerImageID:   "contaimageid",
  1281  		ContainerImageName: "container_image_name",
  1282  	}
  1283  
  1284  	l, err := New(info)
  1285  	if err != nil {
  1286  		t.Fatal(err)
  1287  	}
  1288  
  1289  	ctx, unblock := context.WithCancel(context.Background())
  1290  	hec.withBlock(ctx)
  1291  	defer unblock()
  1292  
  1293  	batchSendTimeout = 1 * time.Second
  1294  
  1295  	if err := l.Log(&logger.Message{}); err != nil {
  1296  		t.Fatal(err)
  1297  	}
  1298  
  1299  	done := make(chan struct{})
  1300  	go func() {
  1301  		l.Close()
  1302  		close(done)
  1303  	}()
  1304  
  1305  	select {
  1306  	case <-time.After(60 * time.Second):
  1307  		buf := make([]byte, 1e6)
  1308  		buf = buf[:runtime.Stack(buf, true)]
  1309  		t.Logf("STACK DUMP: \n\n%s\n\n", string(buf))
  1310  		t.Fatal("timeout waiting for close to finish")
  1311  	case <-done:
  1312  	}
  1313  }