github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/statslogger/config_test.go (about)

     1  package statslogger
     2  
     3  /*
     4   * Test the statistics logger.
     5   *
     6   * Most of this file is copied from swiftclient/api_test.go because we want to
     7   * perform some swift client operations where we can look at the updated
     8   * statistics.
     9   */
    10  
    11  import (
    12  	"bytes"
    13  	"errors"
    14  	"fmt"
    15  	"math/rand"
    16  	"sync"
    17  	"testing"
    18  	"time"
    19  
    20  	"golang.org/x/sys/unix"
    21  
    22  	"github.com/swiftstack/ProxyFS/conf"
    23  	"github.com/swiftstack/ProxyFS/ramswift"
    24  	"github.com/swiftstack/ProxyFS/swiftclient"
    25  	"github.com/swiftstack/ProxyFS/transitions"
    26  )
    27  
    28  func (tOCCS *testObjectCopyCallbackStruct) BytesRemaining(bytesRemaining uint64) (chunkSize uint64) {
    29  	chunkSize = tOCCS.chunkSize
    30  	return
    31  }
    32  
    33  type testObjectCopyCallbackStruct struct {
    34  	srcAccountName   string
    35  	srcContainerName string
    36  	srcObjectName    string
    37  	dstAccountName   string
    38  	dstContainerName string
    39  	dstObjectName    string
    40  	chunkSize        uint64
    41  }
    42  
    43  func TestAPI(t *testing.T) {
    44  	var (
    45  		confMap                conf.ConfMap
    46  		confStrings            []string
    47  		err                    error
    48  		signalHandlerIsArmedWG sync.WaitGroup
    49  	)
    50  
    51  	confStrings = []string{
    52  		"Stats.IPAddr=localhost",
    53  		"Stats.UDPPort=52184",
    54  		"Stats.BufferLength=100",
    55  		"Stats.MaxLatency=1s",
    56  
    57  		"StatsLogger.Period=0m",
    58  		"StatsLogger.Verbose=false",
    59  
    60  		"SwiftClient.NoAuthIPAddr=127.0.0.1",
    61  		"SwiftClient.NoAuthTCPPort=9999",
    62  		"SwiftClient.Timeout=10s",
    63  		"SwiftClient.RetryLimit=5",
    64  		"SwiftClient.RetryLimitObject=5",
    65  		"SwiftClient.RetryDelay=250ms",
    66  		"SwiftClient.RetryDelayObject=250ms",
    67  		"SwiftClient.RetryExpBackoff=1.2",
    68  		"SwiftClient.RetryExpBackoffObject=2.0",
    69  		"SwiftClient.ChunkedConnectionPoolSize=64",
    70  		"SwiftClient.NonChunkedConnectionPoolSize=32",
    71  
    72  		"Cluster.WhoAmI=Peer0",
    73  
    74  		"Peer:Peer0.ReadCacheQuotaFraction=0.20",
    75  
    76  		"FSGlobals.VolumeGroupList=",
    77  		"FSGlobals.CheckpointHeaderConsensusAttempts=5",
    78  		"FSGlobals.MountRetryLimit=6",
    79  		"FSGlobals.MountRetryDelay=1s",
    80  		"FSGlobals.MountRetryExpBackoff=2",
    81  		"FSGlobals.LogCheckpointHeaderPosts=true",
    82  		"FSGlobals.TryLockBackoffMin=10ms",
    83  		"FSGlobals.TryLockBackoffMax=50ms",
    84  		"FSGlobals.TryLockSerializationThreshhold=5",
    85  		"FSGlobals.SymlinkMax=32",
    86  		"FSGlobals.CoalesceElementChunkSize=16",
    87  		"FSGlobals.EtcdEnabled=false",
    88  
    89  		"RamSwiftInfo.MaxAccountNameLength=256",
    90  		"RamSwiftInfo.MaxContainerNameLength=256",
    91  		"RamSwiftInfo.MaxObjectNameLength=1024",
    92  		"RamSwiftInfo.AccountListingLimit=10000",
    93  		"RamSwiftInfo.ContainerListingLimit=10000",
    94  	}
    95  
    96  	confMap, err = conf.MakeConfMapFromStrings(confStrings)
    97  	if err != nil {
    98  		t.Fatalf("%v", err)
    99  	}
   100  
   101  	signalHandlerIsArmedWG.Add(1)
   102  	doneChan := make(chan bool, 1) // Must be buffered to avoid race
   103  
   104  	go ramswift.Daemon("/dev/null", confStrings, &signalHandlerIsArmedWG, doneChan, unix.SIGTERM)
   105  
   106  	signalHandlerIsArmedWG.Wait()
   107  
   108  	err = transitions.Up(confMap)
   109  	if nil != err {
   110  		t.Fatalf("transitions.Up(confMap) failed: %v", err)
   111  	}
   112  
   113  	if globals.statsLogPeriod != 0 {
   114  		t.Fatalf("after Up('StatsLogger.Period=0s') globals.statsLogPeriod != 0")
   115  	}
   116  
   117  	err = confMap.UpdateFromString("StatsLogger.Period=1s")
   118  	if nil != err {
   119  		t.Fatalf("UpdateFromString('StatsLogger.Period=1s') failed: %v", err)
   120  	}
   121  
   122  	err = transitions.Signaled(confMap)
   123  	if nil != err {
   124  		t.Fatalf("transitions.Signaled(confMap) failed: %v", err)
   125  	}
   126  
   127  	if globals.statsLogPeriod != 1*time.Second {
   128  		t.Fatalf("after Signaled('StatsLogger.Period=1s') globals.statsLogPeriod != 1 sec")
   129  	}
   130  
   131  	// Run the tests
   132  	//
   133  	// "Real" unit tests would verify the information written into the log
   134  	//
   135  	// t.Run("testRetry", testRetry)
   136  	// t.Run("testOps", testOps)
   137  	testOps(t)
   138  	testChunkedPut(t)
   139  	testReload(t, confMap)
   140  
   141  	// Shutdown packages
   142  
   143  	err = transitions.Down(confMap)
   144  	if nil != err {
   145  		t.Fatalf("transitions.Down(confMap) failed: %v", err)
   146  	}
   147  
   148  	// Send ourself a SIGTERM to terminate ramswift.Daemon()
   149  
   150  	unix.Kill(unix.Getpid(), unix.SIGTERM)
   151  
   152  	_ = <-doneChan
   153  }
   154  
   155  // Test normal Swift client operations so we have something in the log
   156  //
   157  func testOps(t *testing.T) {
   158  	// headers for testing
   159  
   160  	catDogHeaderMap := make(map[string][]string)
   161  	catDogHeaderMap["Cat"] = []string{"Dog"}
   162  
   163  	mouseBirdHeaderMap := make(map[string][]string)
   164  	mouseBirdHeaderMap["Mouse"] = []string{"Bird"}
   165  
   166  	mouseDeleteHeaderMap := make(map[string][]string)
   167  	mouseDeleteHeaderMap["Mouse"] = []string{""}
   168  
   169  	// Send a PUT for account "TestAccount" and header Cat: Dog
   170  
   171  	err := swiftclient.AccountPut("TestAccount", catDogHeaderMap)
   172  	if nil != err {
   173  		tErr := fmt.Sprintf("AccountPut(\"TestAccount\", catDogHeaderMap) failed: %v", err)
   174  		t.Fatalf(tErr)
   175  	}
   176  
   177  	// Send a HEAD for account "TestAccount" expecting header Cat: Dog
   178  
   179  	accountHeaders, err := swiftclient.AccountHead("TestAccount")
   180  	if nil != err {
   181  		tErr := fmt.Sprintf("AccountHead(\"TestAccount\") failed: %v", err)
   182  		t.Fatalf(tErr)
   183  	}
   184  	accountCatHeader, ok := accountHeaders["Cat"]
   185  	if !ok {
   186  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\"")
   187  	}
   188  	if (1 != len(accountCatHeader)) || ("Dog" != accountCatHeader[0]) {
   189  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   190  	}
   191  
   192  	// Send a GET for account "TestAccount" expecting header Cat: Dog and containerList []string{}
   193  
   194  	accountHeaders, containerList, err := swiftclient.AccountGet("TestAccount")
   195  	if nil != err {
   196  		tErr := fmt.Sprintf("AccountGet(\"TestAccount\") failed: %v", err)
   197  		t.Fatalf(tErr)
   198  	}
   199  	accountCatHeader, ok = accountHeaders["Cat"]
   200  	if !ok {
   201  		t.Fatalf("AccountGet(\"TestAccount\") didn't return Header \"Cat\"")
   202  	}
   203  	if (1 != len(accountCatHeader)) || ("Dog" != accountCatHeader[0]) {
   204  		t.Fatalf("AccountGet(\"TestAccount\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   205  	}
   206  	if 0 != len(containerList) {
   207  		t.Fatalf("AccountGet(\"TestAccount\") didn't return expected containerList")
   208  	}
   209  
   210  	// Send a POST for account "TestAccount" adding header Mouse: Bird
   211  
   212  	err = swiftclient.AccountPost("TestAccount", mouseBirdHeaderMap)
   213  	if nil != err {
   214  		tErr := fmt.Sprintf("AccountPost(\"TestAccount\", mouseBirdHeaderMap) failed: %v", err)
   215  		t.Fatalf(tErr)
   216  	}
   217  
   218  	// Send a HEAD for account "TestAccount" expecting header Cat: Dog & Mouse: Bird
   219  
   220  	accountHeaders, err = swiftclient.AccountHead("TestAccount")
   221  	if nil != err {
   222  		tErr := fmt.Sprintf("AccountHead(\"TestAccount\") failed: %v", err)
   223  		t.Fatalf(tErr)
   224  	}
   225  	accountCatHeader, ok = accountHeaders["Cat"]
   226  	if !ok {
   227  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\"")
   228  	}
   229  	if (1 != len(accountCatHeader)) || ("Dog" != accountCatHeader[0]) {
   230  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   231  	}
   232  	mouseBirdHeader, ok := accountHeaders["Mouse"]
   233  	if !ok {
   234  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Mouse\"")
   235  	}
   236  	if (1 != len(mouseBirdHeader)) || ("Bird" != mouseBirdHeader[0]) {
   237  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Bird\" having value []string{\"Mouse\"}")
   238  	}
   239  
   240  	// Send a POST for account "TestAccount" deleting header Mouse
   241  
   242  	err = swiftclient.AccountPost("TestAccount", mouseDeleteHeaderMap)
   243  	if nil != err {
   244  		tErr := fmt.Sprintf("AccountPost(\"TestAccount\", mouseDeleteHeaderMap) failed: %v", err)
   245  		t.Fatalf(tErr)
   246  	}
   247  
   248  	// Send a HEAD for account "TestAccount" expecting header Cat: Dog & no Mouse header
   249  
   250  	accountHeaders, err = swiftclient.AccountHead("TestAccount")
   251  	if nil != err {
   252  		tErr := fmt.Sprintf("AccountHead(\"TestAccount\") failed: %v", err)
   253  		t.Fatalf(tErr)
   254  	}
   255  	accountCatHeader, ok = accountHeaders["Cat"]
   256  	if !ok {
   257  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\"")
   258  	}
   259  	if (1 != len(accountCatHeader)) || ("Dog" != accountCatHeader[0]) {
   260  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   261  	}
   262  	_, ok = accountHeaders["Mouse"]
   263  	if ok {
   264  		t.Fatalf("AccountHead(\"TestAccount\") shouldn't have returned Header \"Mouse\"")
   265  	}
   266  
   267  	// Send a PUT for account "TestAccount" adding header Mouse: Bird
   268  
   269  	err = swiftclient.AccountPut("TestAccount", mouseBirdHeaderMap)
   270  	if nil != err {
   271  		tErr := fmt.Sprintf("AccountPut(\"TestAccount\", mouseBirdHeaderMap) failed: %v", err)
   272  		t.Fatalf(tErr)
   273  	}
   274  
   275  	// Send a HEAD for account "TestAccount" expecting header Cat: Dog & Mouse: Bird
   276  
   277  	accountHeaders, err = swiftclient.AccountHead("TestAccount")
   278  	if nil != err {
   279  		tErr := fmt.Sprintf("AccountHead(\"TestAccount\") failed: %v", err)
   280  		t.Fatalf(tErr)
   281  	}
   282  	accountCatHeader, ok = accountHeaders["Cat"]
   283  	if !ok {
   284  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\"")
   285  	}
   286  	if (1 != len(accountCatHeader)) || ("Dog" != accountCatHeader[0]) {
   287  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   288  	}
   289  	mouseBirdHeader, ok = accountHeaders["Mouse"]
   290  	if !ok {
   291  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Mouse\"")
   292  	}
   293  	if (1 != len(mouseBirdHeader)) || ("Bird" != mouseBirdHeader[0]) {
   294  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Bird\" having value []string{\"Mouse\"}")
   295  	}
   296  
   297  	// Send a PUT for account "TestAccount" deleting header Mouse
   298  
   299  	err = swiftclient.AccountPut("TestAccount", mouseDeleteHeaderMap)
   300  	if nil != err {
   301  		tErr := fmt.Sprintf("AccountPut(\"TestAccount\", mouseDeleteHeaderMap) failed: %v", err)
   302  		t.Fatalf(tErr)
   303  	}
   304  
   305  	// Send a HEAD for account "TestAccount" expecting header Cat: Dog & no Mouse header
   306  
   307  	accountHeaders, err = swiftclient.AccountHead("TestAccount")
   308  	if nil != err {
   309  		tErr := fmt.Sprintf("AccountHead(\"TestAccount\") failed: %v", err)
   310  		t.Fatalf(tErr)
   311  	}
   312  	accountCatHeader, ok = accountHeaders["Cat"]
   313  	if !ok {
   314  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\"")
   315  	}
   316  	if (1 != len(accountCatHeader)) || ("Dog" != accountCatHeader[0]) {
   317  		t.Fatalf("AccountHead(\"TestAccount\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   318  	}
   319  	_, ok = accountHeaders["Mouse"]
   320  	if ok {
   321  		t.Fatalf("AccountHead(\"TestAccount\") shouldn't have returned Header \"Mouse\"")
   322  	}
   323  
   324  	// Send a PUT for container "TestContainer" and header Cat: Dog
   325  
   326  	err = swiftclient.ContainerPut("TestAccount", "TestContainer", catDogHeaderMap)
   327  	if nil != err {
   328  		tErr := fmt.Sprintf("ContainerPut(\"TestAccount\", \"TestContainer\", catDogHeaderMap) failed: %v", err)
   329  		t.Fatalf(tErr)
   330  	}
   331  
   332  	// Send a GET for account "TestAccount" expecting header Cat: Dog and containerList []string{"TestContainer"}
   333  
   334  	accountHeaders, containerList, err = swiftclient.AccountGet("TestAccount")
   335  	if nil != err {
   336  		tErr := fmt.Sprintf("AccountGet(\"TestAccount\") failed: %v", err)
   337  		t.Fatalf(tErr)
   338  	}
   339  	accountCatHeader, ok = accountHeaders["Cat"]
   340  	if !ok {
   341  		t.Fatalf("AccountGet(\"TestAccount\") didn't return Header \"Cat\"")
   342  	}
   343  	if (1 != len(accountCatHeader)) || ("Dog" != accountCatHeader[0]) {
   344  		t.Fatalf("AccountGet(\"TestAccount\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   345  	}
   346  	if (1 != len(containerList)) || ("TestContainer" != containerList[0]) {
   347  		t.Fatalf("AccountGet(\"TestAccount\") didn't return expected containerList")
   348  	}
   349  
   350  	// Send a HEAD for container "TestContainer" expecting header Cat: Dog
   351  
   352  	containerHeaders, err := swiftclient.ContainerHead("TestAccount", "TestContainer")
   353  	if nil != err {
   354  		tErr := fmt.Sprintf("ContainerHead(\"TestAccount\", \"TestContainer\") failed: %v", err)
   355  		t.Fatalf(tErr)
   356  	}
   357  	containerCatHeader, ok := containerHeaders["Cat"]
   358  	if !ok {
   359  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   360  	}
   361  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   362  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   363  	}
   364  
   365  	// Send a GET for container "TestContainer" expecting header Cat: Dog and objectList []string{}
   366  
   367  	containerHeaders, objectList, err := swiftclient.ContainerGet("TestAccount", "TestContainer")
   368  	if nil != err {
   369  		tErr := fmt.Sprintf("ContainerGet(\"TestAccount\", \"TestContainer\") failed: %v", err)
   370  		t.Fatalf(tErr)
   371  	}
   372  	containerCatHeader, ok = containerHeaders["Cat"]
   373  	if !ok {
   374  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   375  	}
   376  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   377  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   378  	}
   379  	if 0 != len(objectList) {
   380  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return expected objectList")
   381  	}
   382  
   383  	// Send a POST for container "TestContainer" adding header Mouse: Bird
   384  
   385  	err = swiftclient.ContainerPost("TestAccount", "TestContainer", mouseBirdHeaderMap)
   386  	if nil != err {
   387  		tErr := fmt.Sprintf("ContainerPost(\"TestAccount\", \"TestContainer\", mouseBirdHeaderMap) failed: %v", err)
   388  		t.Fatalf(tErr)
   389  	}
   390  
   391  	// Send a HEAD for container "TestContainer" expecting header Cat: Dog & Mouse: Bird
   392  
   393  	containerHeaders, err = swiftclient.ContainerHead("TestAccount", "TestContainer")
   394  	if nil != err {
   395  		tErr := fmt.Sprintf("ContainerHead(\"TestAccount\", \"TestContainer\") failed: %v", err)
   396  		t.Fatalf(tErr)
   397  	}
   398  	containerCatHeader, ok = containerHeaders["Cat"]
   399  	if !ok {
   400  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   401  	}
   402  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   403  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   404  	}
   405  	containerMouseHeader, ok := containerHeaders["Mouse"]
   406  	if !ok {
   407  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Mouse\"")
   408  	}
   409  	if (1 != len(containerMouseHeader)) || ("Bird" != containerMouseHeader[0]) {
   410  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Mouse\" having value []string{\"Bird\"}")
   411  	}
   412  
   413  	// Send a POST for container "TestContainer" deleting header Mouse
   414  
   415  	err = swiftclient.ContainerPost("TestAccount", "TestContainer", mouseDeleteHeaderMap)
   416  	if nil != err {
   417  		tErr := fmt.Sprintf("ContainerPost(\"TestAccount\", \"TestContainer\", mouseDeleteHeaderMap) failed: %v", err)
   418  		t.Fatalf(tErr)
   419  	}
   420  
   421  	// Send a HEAD for container "TestContainer" expecting header Cat: Dog & no Mouse header
   422  
   423  	containerHeaders, err = swiftclient.ContainerHead("TestAccount", "TestContainer")
   424  	if nil != err {
   425  		tErr := fmt.Sprintf("ContainerHead(\"TestAccount\", \"TestContainer\") failed: %v", err)
   426  		t.Fatalf(tErr)
   427  	}
   428  	containerCatHeader, ok = containerHeaders["Cat"]
   429  	if !ok {
   430  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   431  	}
   432  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   433  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   434  	}
   435  	_, ok = containerHeaders["Mouse"]
   436  	if ok {
   437  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") shouldn't have returned Header \"Mouse\"")
   438  	}
   439  
   440  	// Send a PUT for container "TestContainer" adding header Mouse: Bird
   441  
   442  	err = swiftclient.ContainerPut("TestAccount", "TestContainer", mouseBirdHeaderMap)
   443  	if nil != err {
   444  		tErr := fmt.Sprintf("ContainerPut(\"TestAccount\", \"TestContainer\", mouseBirdHeaderMap) failed: %v", err)
   445  		t.Fatalf(tErr)
   446  	}
   447  
   448  	// Send a HEAD for container "TestContainer" expecting header Cat: Dog & Mouse: Bird
   449  
   450  	containerHeaders, err = swiftclient.ContainerHead("TestAccount", "TestContainer")
   451  	if nil != err {
   452  		tErr := fmt.Sprintf("ContainerHead(\"TestAccount\", \"TestContainer\") failed: %v", err)
   453  		t.Fatalf(tErr)
   454  	}
   455  	containerCatHeader, ok = containerHeaders["Cat"]
   456  	if !ok {
   457  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   458  	}
   459  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   460  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   461  	}
   462  	containerMouseHeader, ok = containerHeaders["Mouse"]
   463  	if !ok {
   464  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Mouse\"")
   465  	}
   466  	if (1 != len(containerMouseHeader)) || ("Bird" != containerMouseHeader[0]) {
   467  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Mouse\" having value []string{\"Bird\"}")
   468  	}
   469  
   470  	// Send a PUT for container "TestContainer" deleting header Mouse
   471  
   472  	err = swiftclient.ContainerPut("TestAccount", "TestContainer", mouseDeleteHeaderMap)
   473  	if nil != err {
   474  		tErr := fmt.Sprintf("ContainerPut(\"TestAccount\", \"TestContainer\", mouseDeleteHeaderMap) failed: %v", err)
   475  		t.Fatalf(tErr)
   476  	}
   477  
   478  	// Send a HEAD for container "TestContainer" expecting header Cat: Dog & no Mouse header
   479  
   480  	containerHeaders, err = swiftclient.ContainerHead("TestAccount", "TestContainer")
   481  	if nil != err {
   482  		tErr := fmt.Sprintf("ContainerHead(\"TestAccount\", \"TestContainer\") failed: %v", err)
   483  		t.Fatalf(tErr)
   484  	}
   485  	containerCatHeader, ok = containerHeaders["Cat"]
   486  	if !ok {
   487  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   488  	}
   489  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   490  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   491  	}
   492  	_, ok = containerHeaders["Mouse"]
   493  	if ok {
   494  		t.Fatalf("ContainerHead(\"TestAccount\", \"TestContainer\") shouldn't have returned Header \"Mouse\"")
   495  	}
   496  
   497  	// Start a chunked PUT for object "FooBar"
   498  
   499  	chunkedPutContext, err := swiftclient.ObjectFetchChunkedPutContext("TestAccount", "TestContainer", "FooBar", "")
   500  	if nil != err {
   501  		tErr := fmt.Sprintf("ObjectFetchChunkedPutContext(\"TestAccount\", \"TestContainer\") failed: %v", err)
   502  		t.Fatalf(tErr)
   503  	}
   504  
   505  	// Send a chunk for object "FooBar" of []byte{0xAA, 0xBB}
   506  
   507  	err = chunkedPutContext.SendChunk([]byte{0xAA, 0xBB})
   508  	if nil != err {
   509  		tErr := fmt.Sprintf("chunkedPutContext.SendChunk([]byte{0xAA, 0xBB}) failed: %v", err)
   510  		t.Fatalf(tErr)
   511  	}
   512  
   513  	// Send a chunk for object "FooBar" of []byte{0xCC, 0xDD, 0xEE}
   514  
   515  	err = chunkedPutContext.SendChunk([]byte{0xCC, 0xDD, 0xEE})
   516  	if nil != err {
   517  		tErr := fmt.Sprintf("chunkedPutContext.SendChunk([]byte{0xCC, 0xDD, 0xEE}) failed: %v", err)
   518  		t.Fatalf(tErr)
   519  	}
   520  
   521  	// Fetch BytesPut for object "FooBar" expecting 5
   522  
   523  	bytesPut, err := chunkedPutContext.BytesPut()
   524  	if nil != err {
   525  		tErr := fmt.Sprintf("chunkedPutContext.BytesPut() failed: %v", err)
   526  		t.Fatalf(tErr)
   527  	}
   528  	if 5 != bytesPut {
   529  		t.Fatalf("chunkedPutContext.BytesPut() didn't return expected bytesPut")
   530  	}
   531  
   532  	// Read back chunked PUT data at offset 1 for length 3 expecting []byte{0xBB, 0xCC, 0xDD}
   533  
   534  	readBuf, err := chunkedPutContext.Read(uint64(1), uint64(3))
   535  	if nil != err {
   536  		tErr := fmt.Sprintf("chunkedPutContext.Read(uint64(1), uint64(3)) failed: %v", err)
   537  		t.Fatalf(tErr)
   538  	}
   539  	if 0 != bytes.Compare([]byte{0xBB, 0xCC, 0xDD}, readBuf) {
   540  		t.Fatalf("chunkedPutContext.Read(uint64(1), uint64(3)) didn't return expected []byte")
   541  	}
   542  
   543  	// Finish the chunked PUT for object "FooBar"
   544  
   545  	err = chunkedPutContext.Close()
   546  	if nil != err {
   547  		tErr := fmt.Sprintf("chunkedPutContext.Close() failed: %v", err)
   548  		t.Fatalf(tErr)
   549  	}
   550  
   551  	// Send a GET for container "TestContainer" expecting header Cat: Dog and objectList []string{"FooBar"}
   552  
   553  	containerHeaders, objectList, err = swiftclient.ContainerGet("TestAccount", "TestContainer")
   554  	if nil != err {
   555  		tErr := fmt.Sprintf("ContainerGet(\"TestAccount\", \"TestContainer\") failed: %v", err)
   556  		t.Fatalf(tErr)
   557  	}
   558  	containerCatHeader, ok = containerHeaders["Cat"]
   559  	if !ok {
   560  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   561  	}
   562  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   563  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   564  	}
   565  	if (1 != len(objectList)) || ("FooBar" != objectList[0]) {
   566  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return expected objectList")
   567  	}
   568  
   569  	// Send a HEAD for object "FooBar" expecting Content-Length: 5
   570  
   571  	objectHeaders, err := swiftclient.ObjectHead("TestAccount", "TestContainer", "FooBar")
   572  	if nil != err {
   573  		tErr := fmt.Sprintf("ObjectHead(\"TestAccount\", \"TestContainer\", \"FooBar\") failed: %v", err)
   574  		t.Fatalf(tErr)
   575  	}
   576  	contentLengthHeader, ok := objectHeaders["Content-Length"]
   577  	if !ok {
   578  		t.Fatalf("ObjectHead(\"TestAccount\", \"TestContainer\", \"FooBar\") didn't return Header \"Content-Length\"")
   579  	}
   580  	if (1 != len(contentLengthHeader)) || ("5" != contentLengthHeader[0]) {
   581  		t.Fatalf("ObjectHead(\"TestAccount\", \"TestContainer\", \"FooBar\") didn't return Header \"Content-Length\" having value []string{\"5\"}")
   582  	}
   583  
   584  	// Fetch Content-Length for object "FooBar" expecting 5
   585  
   586  	objectLength, err := swiftclient.ObjectContentLength("TestAccount", "TestContainer", "FooBar")
   587  	if nil != err {
   588  		tErr := fmt.Sprintf("ObjectContentLength(\"TestAccount\", \"TestContainer\", \"FooBar\") failed: %v", err)
   589  		t.Fatalf(tErr)
   590  	}
   591  	if uint64(5) != objectLength {
   592  		tErr := fmt.Sprintf("ObjectContentLength(\"TestAccount\", \"TestContainer\", \"FooBar\") didn't return expected Content-Length")
   593  		t.Fatalf(tErr)
   594  	}
   595  
   596  	// Send a range GET of bytes at offset 1 for length 3 for object "FooBar" expecting []byte{0xBB, 0xCC, 0xDD}
   597  
   598  	getBuf, err := swiftclient.ObjectGet("TestAccount", "TestContainer", "FooBar", uint64(1), uint64(3))
   599  	if nil != err {
   600  		tErr := fmt.Sprintf("ObjectGet(\"TestAccount\", \"TestContainer\", \"FooBar\", uint64(1), uint64(3)) failed: %v", err)
   601  		t.Fatalf(tErr)
   602  	}
   603  	if 0 != bytes.Compare([]byte{0xBB, 0xCC, 0xDD}, getBuf) {
   604  		tErr := fmt.Sprintf("ObjectGet(\"TestAccount\", \"TestContainer\", \"FooBar\", uint64(1), uint64(3)) didn't return expected []byte")
   605  		t.Fatalf(tErr)
   606  	}
   607  
   608  	// Send a full GET for object "FooBar" expecting []byte{0xAA, 0xBB, 0xCC, 0xDD, OxEE}
   609  
   610  	loadBuf, err := swiftclient.ObjectLoad("TestAccount", "TestContainer", "FooBar")
   611  	if nil != err {
   612  		tErr := fmt.Sprintf("ObjectLoad(\"TestAccount\", \"TestContainer\", \"FooBar\") failed: %v", err)
   613  		t.Fatalf(tErr)
   614  	}
   615  	if 0 != bytes.Compare([]byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE}, loadBuf) {
   616  		tErr := fmt.Sprintf("ObjectLoad(\"TestAccount\", \"TestContainer\", \"FooBar\") didn't return expected []byte")
   617  		t.Fatalf(tErr)
   618  	}
   619  
   620  	// Send a tail GET of the last 2 bytes for object "FooBar" expecting []byte{0xDD, 0xEE}
   621  
   622  	tailBuf, err := swiftclient.ObjectTail("TestAccount", "TestContainer", "FooBar", uint64(2))
   623  	if nil != err {
   624  		tErr := fmt.Sprintf("ObjectTail(\"TestAccount\", \"TestContainer\", \"FooBar\", uint64(2)) failed: %v", err)
   625  		t.Fatalf(tErr)
   626  	}
   627  	if 0 != bytes.Compare([]byte{0xDD, 0xEE}, tailBuf) {
   628  		tErr := fmt.Sprintf("ObjectTail(\"TestAccount\", \"TestContainer\", \"FooBar\", uint64(2)) didn't return expected []byte")
   629  		t.Fatalf(tErr)
   630  	}
   631  
   632  	// Copy object "FooBar" to object "FooBarCopy"
   633  
   634  	tOCCS := &testObjectCopyCallbackStruct{
   635  		srcAccountName:   "TestAccount",
   636  		srcContainerName: "TestContainer",
   637  		srcObjectName:    "FooBar",
   638  		dstAccountName:   "TestAccount",
   639  		dstContainerName: "TestContainer",
   640  		dstObjectName:    "FooBarCopy",
   641  		chunkSize:        1, // Causes a callback for each of the five bytes of FooBar
   642  	}
   643  
   644  	err = swiftclient.ObjectCopy(tOCCS.srcAccountName, tOCCS.srcContainerName, tOCCS.srcObjectName, tOCCS.dstAccountName, tOCCS.dstContainerName, tOCCS.dstObjectName, tOCCS)
   645  	if nil != err {
   646  		tErr := fmt.Sprintf("ObjectCopy(\"TestAccount/TestContainer/FooBar\" to \"TestAccount/TestContainer/FooBarCopy\") failed: %v", err)
   647  		t.Fatalf(tErr)
   648  	}
   649  
   650  	// Send a full GET for object "FooBarCopy" expecting []byte{0xAA, 0xBB, 0xCC, 0xDD, OxEE}
   651  
   652  	loadBuf, err = swiftclient.ObjectLoad("TestAccount", "TestContainer", "FooBarCopy")
   653  	if nil != err {
   654  		tErr := fmt.Sprintf("ObjectLoad(\"TestAccount\", \"TestContainer\", \"FooBarCopy\") failed: %v", err)
   655  		t.Fatalf(tErr)
   656  	}
   657  	if 0 != bytes.Compare([]byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE}, loadBuf) {
   658  		tErr := fmt.Sprintf("ObjectLoad(\"TestAccount\", \"TestContainer\", \"FooBarCopy\") didn't return expected []byte")
   659  		t.Fatalf(tErr)
   660  	}
   661  
   662  	// Send a GET for container "TestContainer" expecting header Cat: Dog and objectList []string{"FooBar", "FooBarCopy"}
   663  
   664  	containerHeaders, objectList, err = swiftclient.ContainerGet("TestAccount", "TestContainer")
   665  	if nil != err {
   666  		tErr := fmt.Sprintf("ContainerGet(\"TestAccount\", \"TestContainer\") failed: %v", err)
   667  		t.Fatalf(tErr)
   668  	}
   669  	containerCatHeader, ok = containerHeaders["Cat"]
   670  	if !ok {
   671  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   672  	}
   673  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   674  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   675  	}
   676  	if (2 != len(objectList)) || ("FooBar" != objectList[0]) || ("FooBarCopy" != objectList[1]) {
   677  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return expected objectList")
   678  	}
   679  
   680  	// Send a DELETE for object "FooBar"
   681  
   682  	err = swiftclient.ObjectDelete("TestAccount", "TestContainer", "FooBar", 0)
   683  	if nil != err {
   684  		tErr := fmt.Sprintf("ObjectDelete(\"TestAccount\", \"TestContainer\". \"FooBar\", 0) failed: %v", err)
   685  		t.Fatalf(tErr)
   686  	}
   687  
   688  	// Send a GET for container "TestContainer" expecting header Cat: Dog and objectList []string{"FooBarCopy"}
   689  
   690  	containerHeaders, objectList, err = swiftclient.ContainerGet("TestAccount", "TestContainer")
   691  	if nil != err {
   692  		tErr := fmt.Sprintf("ContainerGet(\"TestAccount\", \"TestContainer\") failed: %v", err)
   693  		t.Fatalf(tErr)
   694  	}
   695  	containerCatHeader, ok = containerHeaders["Cat"]
   696  	if !ok {
   697  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   698  	}
   699  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   700  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   701  	}
   702  	if (1 != len(objectList)) || ("FooBarCopy" != objectList[0]) {
   703  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return expected objectList")
   704  	}
   705  
   706  	// Send a DELETE for object "FooBarCopy"
   707  
   708  	err = swiftclient.ObjectDelete("TestAccount", "TestContainer", "FooBarCopy", 0)
   709  	if nil != err {
   710  		tErr := fmt.Sprintf("ObjectDelete(\"TestAccount\", \"TestContainer\". \"FooBarCopy\", 0) failed: %v", err)
   711  		t.Fatalf(tErr)
   712  	}
   713  
   714  	// Send a GET for container "TestContainer" expecting header Cat: Dog and objectList []string{}
   715  
   716  	containerHeaders, objectList, err = swiftclient.ContainerGet("TestAccount", "TestContainer")
   717  	if nil != err {
   718  		tErr := fmt.Sprintf("ContainerGet(\"TestAccount\", \"TestContainer\") failed: %v", err)
   719  		t.Fatalf(tErr)
   720  	}
   721  	containerCatHeader, ok = containerHeaders["Cat"]
   722  	if !ok {
   723  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\"")
   724  	}
   725  	if (1 != len(containerCatHeader)) || ("Dog" != containerCatHeader[0]) {
   726  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   727  	}
   728  	if 0 != len(objectList) {
   729  		t.Fatalf("ContainerGet(\"TestAccount\", \"TestContainer\") didn't return expected objectList")
   730  	}
   731  
   732  	// Send a DELETE for container "TestContainer"
   733  
   734  	err = swiftclient.ContainerDelete("TestAccount", "TestContainer")
   735  	if nil != err {
   736  		tErr := fmt.Sprintf("ContainerDelete(\"TestAccount\", \"TestContainer\") failed: %v", err)
   737  		t.Fatalf(tErr)
   738  	}
   739  
   740  	// create and delete container "TestContainer" again so we're sure the retry code is hit
   741  
   742  	err = swiftclient.ContainerPut("TestAccount", "TestContainer", catDogHeaderMap)
   743  	if nil != err {
   744  		tErr := fmt.Sprintf("ContainerPut(\"TestAccount\", \"TestContainer\", catDogHeaderMap) failed: %v", err)
   745  		t.Fatalf(tErr)
   746  	}
   747  	err = swiftclient.ContainerDelete("TestAccount", "TestContainer")
   748  	if nil != err {
   749  		tErr := fmt.Sprintf("ContainerDelete(\"TestAccount\", \"TestContainer\") failed: %v", err)
   750  		t.Fatalf(tErr)
   751  	}
   752  
   753  	// Send a GET for account "TestAccount" expecting header Cat: Dog and containerList []string{}
   754  
   755  	accountHeaders, containerList, err = swiftclient.AccountGet("TestAccount")
   756  	if nil != err {
   757  		tErr := fmt.Sprintf("AccountGet(\"TestAccount\") failed: %v", err)
   758  		t.Fatalf(tErr)
   759  	}
   760  	accountCatHeader, ok = accountHeaders["Cat"]
   761  	if !ok {
   762  		t.Fatalf("AccountGet(\"TestAccount\") didn't return Header \"Cat\"")
   763  	}
   764  	if (1 != len(accountCatHeader)) || ("Dog" != accountCatHeader[0]) {
   765  		t.Fatalf("AccountGet(\"TestAccount\") didn't return Header \"Cat\" having value []string{\"Dog\"}")
   766  	}
   767  	if 0 != len(containerList) {
   768  		t.Fatalf("AccountGet(\"TestAccount\") didn't return expected containerList")
   769  	}
   770  
   771  	// Send a DELETE for account "TestAccount"
   772  
   773  	err = swiftclient.AccountDelete("TestAccount")
   774  	if nil != err {
   775  		tErr := fmt.Sprintf("AccountDelete(\"TestAccount\") failed: %v", err)
   776  		t.Fatalf(tErr)
   777  	}
   778  
   779  	// Create and delete "TestAccount" again so we're sure the retry code is hit
   780  
   781  	err = swiftclient.AccountPut("TestAccount", catDogHeaderMap)
   782  	if nil != err {
   783  		tErr := fmt.Sprintf("AccountPut(\"TestAccount\", catDogHeaderMap) failed: %v", err)
   784  		t.Fatalf(tErr)
   785  	}
   786  	err = swiftclient.AccountDelete("TestAccount")
   787  	if nil != err {
   788  		tErr := fmt.Sprintf("AccountDelete(\"TestAccount\") failed: %v", err)
   789  		t.Fatalf(tErr)
   790  	}
   791  }
   792  
   793  // Extended testing of chunked put interface to exercise internal retries
   794  //
   795  func testChunkedPut(t *testing.T) {
   796  	var (
   797  		accountName   = "TestAccount"
   798  		containerName = "TestContainer"
   799  		objNameFmt    = "chunkObj%d"
   800  		objName       string
   801  	)
   802  
   803  	// (lack of) headers for putting
   804  	catDogHeaderMap := make(map[string][]string)
   805  
   806  	// (re)create the test account and continer
   807  
   808  	err := swiftclient.AccountPut(accountName, catDogHeaderMap)
   809  	if nil != err {
   810  		tErr := fmt.Sprintf("testChunkedPut.AccountPut('%s', catDogHeaderMap) failed: %v", accountName, err)
   811  		t.Fatalf(tErr)
   812  	}
   813  
   814  	err = swiftclient.ContainerPut(accountName, containerName, catDogHeaderMap)
   815  	if nil != err {
   816  		tErr := fmt.Sprintf("testChunkedPut.ContainerPut('%s', '%s', catDogHeaderMap) failed: %v",
   817  			accountName, containerName, err)
   818  		t.Fatalf(tErr)
   819  	}
   820  
   821  	for i := 0; i < 5; i++ {
   822  		objName = fmt.Sprintf(objNameFmt, i)
   823  
   824  		err = testObjectWriteVerify(t, accountName, containerName, objName, 4096, 4)
   825  		if nil != err {
   826  			tErr := fmt.Sprintf("testChunkedPut.testObjectWriteVerify('%s/%s/%s', %d, %d ) failed: %v",
   827  				accountName, containerName, objName, 4096, 4, err)
   828  			t.Fatalf(tErr)
   829  		}
   830  	}
   831  
   832  	// cleanup the mess we made (objects, container, and account)
   833  	for i := 0; i < 5; i++ {
   834  		objName = fmt.Sprintf(objNameFmt, i)
   835  
   836  		err = swiftclient.ObjectDelete(accountName, containerName, objName, 0)
   837  		if nil != err {
   838  			tErr := fmt.Sprintf("ObjectDelete('%s', '%s', '%s') failed: %v",
   839  				accountName, containerName, objName, err)
   840  			t.Fatalf(tErr)
   841  		}
   842  	}
   843  
   844  	err = swiftclient.ContainerDelete(accountName, containerName)
   845  	if nil != err {
   846  		tErr := fmt.Sprintf("ContainerDelete('%s', '%s') failed: %v", accountName, containerName, err)
   847  		t.Fatalf(tErr)
   848  	}
   849  
   850  	err = swiftclient.AccountDelete(accountName)
   851  	if nil != err {
   852  		tErr := fmt.Sprintf("AccountDelete('%s') failed: %v", accountName, err)
   853  		t.Fatalf(tErr)
   854  	}
   855  }
   856  
   857  // write objSize worth of random bytes to the object using nWrite calls to
   858  // SendChunk() and then read it back to verify.
   859  //
   860  func testObjectWriteVerify(t *testing.T, accountName string, containerName string, objName string,
   861  	objSize int, nwrite int) (err error) {
   862  
   863  	writeBuf := make([]byte, objSize)
   864  	readBuf := make([]byte, 0)
   865  
   866  	for i := 0; i < objSize; i++ {
   867  		writeBuf[i] = byte(rand.Uint32())
   868  	}
   869  	if writeBuf[0] == 0 && writeBuf[1] == 0 && writeBuf[2] == 0 && writeBuf[3] == 0 {
   870  		tErr := "unix.GetRandom() is not very random"
   871  		t.Fatalf(tErr)
   872  	}
   873  	if writeBuf[objSize-1] == 0 && writeBuf[objSize-2] == 0 && writeBuf[objSize-3] == 0 &&
   874  		writeBuf[objSize-4] == 0 {
   875  		tErr := "unix.GetRandom() is not very radnom at end of buffer"
   876  		t.Fatalf(tErr)
   877  	}
   878  
   879  	// Start a chunked PUT for the object
   880  	chunkedPutContext, err := swiftclient.ObjectFetchChunkedPutContext(accountName, containerName, objName, "")
   881  	if nil != err {
   882  		tErr := fmt.Sprintf("ObjectFetchChunkedPutContext('%s', '%s', '%s') failed: %v",
   883  			accountName, containerName, objName, err)
   884  		return errors.New(tErr)
   885  	}
   886  
   887  	wsz := len(writeBuf) / nwrite
   888  	for off := 0; off < len(writeBuf); off += wsz {
   889  		if off+wsz < objSize {
   890  			err = chunkedPutContext.SendChunk(writeBuf[off : off+wsz])
   891  		} else {
   892  			err = chunkedPutContext.SendChunk(writeBuf[off:])
   893  		}
   894  		if nil != err {
   895  			tErr := fmt.Sprintf("chunkedPutContext.SendChunk(writeBuf[%d:%d]) failed: %v",
   896  				off, off+wsz, err)
   897  			return errors.New(tErr)
   898  		}
   899  	}
   900  	err = chunkedPutContext.Close()
   901  	if nil != err {
   902  		tErr := fmt.Sprintf("chunkedPutContext.Close('%s/%s/%s') failed: %v",
   903  			accountName, containerName, objName, err)
   904  		return errors.New(tErr)
   905  	}
   906  
   907  	// read and compare
   908  	readBuf, err = swiftclient.ObjectLoad(accountName, containerName, objName)
   909  	if nil != err {
   910  		tErr := fmt.Sprintf("ObjectLoad('%s/%s/%s') failed: %v", accountName, containerName, objName, err)
   911  		return errors.New(tErr)
   912  	}
   913  	if !bytes.Equal(readBuf, writeBuf) {
   914  		tErr := fmt.Sprintf("Object('%s/%s/%s') read back something different then written",
   915  			accountName, containerName, objName)
   916  		return errors.New(tErr)
   917  	}
   918  
   919  	return nil
   920  }
   921  
   922  // Make sure we can shutdown and re-enable the statsLogger
   923  //
   924  func testReload(t *testing.T, confMap conf.ConfMap) {
   925  	var err error
   926  
   927  	// Reload statslogger with logging disabled
   928  	err = confMap.UpdateFromString("StatsLogger.Period=0s")
   929  	if nil != err {
   930  		tErr := fmt.Sprintf("UpdateFromString('StatsLogger.Period=0s') failed: %v", err)
   931  		t.Fatalf(tErr)
   932  	}
   933  
   934  	err = transitions.Signaled(confMap)
   935  	if nil != err {
   936  		t.Fatalf("transitions.Signaled(confMap) failed: %v", err)
   937  	}
   938  
   939  	// Enable logging again
   940  	err = confMap.UpdateFromString("StatsLogger.Period=1s")
   941  	if nil != err {
   942  		tErr := fmt.Sprintf("UpdateFromString('StatsLogger.Period=1s') failed: %v", err)
   943  		t.Fatalf(tErr)
   944  	}
   945  
   946  	err = transitions.Signaled(confMap)
   947  	if nil != err {
   948  		t.Fatalf("transitions.Signaled(confMap) failed: %v", err)
   949  	}
   950  }