github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/monitor/host_flagging_test.go (about)

     1  package monitor
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/evergreen-ci/evergreen"
     8  	"github.com/evergreen-ci/evergreen/cloud/providers/mock"
     9  	"github.com/evergreen-ci/evergreen/db"
    10  	"github.com/evergreen-ci/evergreen/model/distro"
    11  	"github.com/evergreen-ci/evergreen/model/host"
    12  	modelUtil "github.com/evergreen-ci/evergreen/model/testutil"
    13  	"github.com/evergreen-ci/evergreen/testutil"
    14  	"github.com/evergreen-ci/evergreen/util"
    15  	. "github.com/smartystreets/goconvey/convey"
    16  )
    17  
    18  func TestFlaggingDecommissionedHosts(t *testing.T) {
    19  
    20  	testConfig := testutil.TestConfig()
    21  
    22  	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testConfig))
    23  
    24  	Convey("When flagging decommissioned hosts", t, func() {
    25  
    26  		Convey("only hosts in the database who are marked decommissioned"+
    27  			" should be returned", func() {
    28  
    29  			// reset the db
    30  			testutil.HandleTestingErr(db.ClearCollections(host.Collection),
    31  				t, "error clearing hosts collection")
    32  
    33  			// insert hosts with different statuses
    34  
    35  			host1 := &host.Host{
    36  				Id:     "h1",
    37  				Status: evergreen.HostRunning,
    38  			}
    39  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
    40  
    41  			host2 := &host.Host{
    42  				Id:     "h2",
    43  				Status: evergreen.HostTerminated,
    44  			}
    45  			testutil.HandleTestingErr(host2.Insert(), t, "error inserting host")
    46  
    47  			host3 := &host.Host{
    48  				Id:     "h3",
    49  				Status: evergreen.HostDecommissioned,
    50  			}
    51  			testutil.HandleTestingErr(host3.Insert(), t, "error inserting host")
    52  
    53  			host4 := &host.Host{
    54  				Id:     "h4",
    55  				Status: evergreen.HostDecommissioned,
    56  			}
    57  			testutil.HandleTestingErr(host4.Insert(), t, "error inserting host")
    58  
    59  			host5 := &host.Host{
    60  				Id:     "h5",
    61  				Status: evergreen.HostQuarantined,
    62  			}
    63  			testutil.HandleTestingErr(host5.Insert(), t, "error inserting host")
    64  
    65  			// flag the decommissioned hosts - there should be 2 of them
    66  			decommissioned, err := flagDecommissionedHosts(nil, testConfig)
    67  			So(err, ShouldBeNil)
    68  			So(len(decommissioned), ShouldEqual, 2)
    69  			var ids []string
    70  			for _, h := range decommissioned {
    71  				ids = append(ids, h.Id)
    72  			}
    73  			So(util.SliceContains(ids, host3.Id), ShouldBeTrue)
    74  			So(util.SliceContains(ids, host4.Id), ShouldBeTrue)
    75  		})
    76  
    77  	})
    78  
    79  }
    80  
    81  func TestFlaggingIdleHosts(t *testing.T) {
    82  
    83  	testConfig := testutil.TestConfig()
    84  
    85  	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testConfig))
    86  
    87  	Convey("When flagging idle hosts to be terminated", t, func() {
    88  
    89  		// reset the db
    90  		testutil.HandleTestingErr(db.ClearCollections(host.Collection),
    91  			t, "error clearing hosts collection")
    92  		testutil.HandleTestingErr(modelUtil.AddTestIndexes(host.Collection,
    93  			true, true, host.RunningTaskKey), t, "error adding host index")
    94  		Convey("hosts currently running a task should never be"+
    95  			" flagged", func() {
    96  
    97  			// insert a host that is currently running a task - but whose
    98  			// creation time would otherwise indicate it has been idle a while
    99  			host1 := host.Host{
   100  				Id:           "h1",
   101  				Provider:     mock.ProviderName,
   102  				CreationTime: time.Now().Add(-30 * time.Minute),
   103  				RunningTask:  "t1",
   104  				Status:       evergreen.HostRunning,
   105  				StartedBy:    evergreen.User,
   106  			}
   107  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   108  
   109  			// finding idle hosts should not return the host
   110  			idle, err := flagIdleHosts(nil, nil)
   111  			So(err, ShouldBeNil)
   112  			So(len(idle), ShouldEqual, 0)
   113  
   114  			Convey("even if they have a last communication time > 10 minutes", func() {
   115  				h2 := host.Host{
   116  					Id:                    "anotherhost",
   117  					Provider:              mock.ProviderName,
   118  					CreationTime:          time.Now().Add(-30 * time.Minute),
   119  					RunningTask:           "t3",
   120  					Status:                evergreen.HostRunning,
   121  					LastCommunicationTime: time.Now().Add(-30 * time.Minute),
   122  					StartedBy:             evergreen.User,
   123  				}
   124  				testutil.HandleTestingErr(h2.Insert(), t, "error inserting host")
   125  				// finding idle hosts should not return the host
   126  				idle, err := flagIdleHosts(nil, nil)
   127  				So(err, ShouldBeNil)
   128  				So(len(idle), ShouldEqual, 0)
   129  
   130  			})
   131  
   132  		})
   133  
   134  		Convey("hosts not currently running a task should be flagged if they"+
   135  			" have been idle at least 15 minutes and will incur a payment in"+
   136  			" less than 10 minutes", func() {
   137  
   138  			// insert two hosts - one whose last task was more than 15 minutes
   139  			// ago, one whose last task was less than 15 minutes ago
   140  
   141  			host1 := host.Host{
   142  				Id:                    "h2",
   143  				Provider:              mock.ProviderName,
   144  				LastTaskCompleted:     "t1",
   145  				LastTaskCompletedTime: time.Now().Add(-time.Minute * 20),
   146  				LastCommunicationTime: time.Now(),
   147  				Status:                evergreen.HostRunning,
   148  				StartedBy:             evergreen.User,
   149  			}
   150  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   151  
   152  			host2 := host.Host{
   153  				Id:                    "h3",
   154  				Provider:              mock.ProviderName,
   155  				LastTaskCompleted:     "t2",
   156  				LastTaskCompletedTime: time.Now().Add(-time.Minute * 5),
   157  				LastCommunicationTime: time.Now(),
   158  				Status:                evergreen.HostRunning,
   159  				StartedBy:             evergreen.User,
   160  			}
   161  			testutil.HandleTestingErr(host2.Insert(), t, "error inserting host")
   162  
   163  			// finding idle hosts should only return the first host
   164  			idle, err := flagIdleHosts(nil, nil)
   165  			So(err, ShouldBeNil)
   166  			So(len(idle), ShouldEqual, 1)
   167  			So(idle[0].Id, ShouldEqual, "h2")
   168  
   169  		})
   170  		Convey("hosts not currently running a task with a last communication time greater"+
   171  			"than 10 mins should be marked as idle", func() {
   172  			anotherHost := host.Host{
   173  				Id:                    "h1",
   174  				Provider:              mock.ProviderName,
   175  				LastCommunicationTime: time.Now().Add(-time.Minute * 20),
   176  				Status:                evergreen.HostRunning,
   177  				StartedBy:             evergreen.User,
   178  			}
   179  			So(anotherHost.Insert(), ShouldBeNil)
   180  			// finding idle hosts should only return the first host
   181  			idle, err := flagIdleHosts(nil, nil)
   182  			So(err, ShouldBeNil)
   183  			So(len(idle), ShouldEqual, 1)
   184  			So(idle[0].Id, ShouldEqual, "h1")
   185  		})
   186  
   187  	})
   188  
   189  }
   190  
   191  func TestFlaggingExcessHosts(t *testing.T) {
   192  
   193  	testConfig := testutil.TestConfig()
   194  
   195  	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testConfig))
   196  
   197  	Convey("When flagging excess hosts to be terminated", t, func() {
   198  
   199  		Convey("with two separate distros containing hosts", func() {
   200  
   201  			// reset the db
   202  			testutil.HandleTestingErr(db.ClearCollections(host.Collection),
   203  				t, "error clearing hosts collection")
   204  
   205  			// mock up the distros
   206  
   207  			distro1 := distro.Distro{
   208  				Id:       "d1",
   209  				PoolSize: 2,
   210  			}
   211  			distro2 := distro.Distro{
   212  				Id:       "d2",
   213  				PoolSize: 1,
   214  			}
   215  			distros := []distro.Distro{distro1, distro2}
   216  
   217  			Convey("if neither distro has excess hosts, no hosts should be"+
   218  				" flagged to be terminated", func() {
   219  
   220  				// insert one host for each distro
   221  
   222  				host1 := &host.Host{
   223  					Id:        "h1",
   224  					Distro:    distro.Distro{Id: "d1"},
   225  					Status:    evergreen.HostRunning,
   226  					StartedBy: evergreen.User,
   227  					Provider:  mock.ProviderName,
   228  				}
   229  				testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   230  
   231  				host2 := &host.Host{
   232  					Id:        "h2",
   233  					Distro:    distro.Distro{Id: "d2"},
   234  					Status:    evergreen.HostRunning,
   235  					StartedBy: evergreen.User,
   236  					Provider:  mock.ProviderName,
   237  				}
   238  				testutil.HandleTestingErr(host2.Insert(), t, "error inserting host")
   239  
   240  				// flag the excess hosts - there should not be any
   241  				excess, err := flagExcessHosts(distros, nil)
   242  				So(err, ShouldBeNil)
   243  				So(len(excess), ShouldEqual, 0)
   244  
   245  			})
   246  
   247  			Convey("if only one distro has excess hosts, the appropriate"+
   248  				" number of hosts from that distro should be flagged", func() {
   249  
   250  				// insert one host for the first distro, and three for the
   251  				// second distro
   252  
   253  				host1 := &host.Host{
   254  					Id:        "h1",
   255  					Distro:    distro.Distro{Id: "d1"},
   256  					Status:    evergreen.HostRunning,
   257  					StartedBy: evergreen.User,
   258  					Provider:  mock.ProviderName,
   259  				}
   260  				testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   261  
   262  				host2 := &host.Host{
   263  					Id:        "h2",
   264  					Distro:    distro.Distro{Id: "d2"},
   265  					Status:    evergreen.HostRunning,
   266  					StartedBy: evergreen.User,
   267  					Provider:  mock.ProviderName,
   268  				}
   269  				testutil.HandleTestingErr(host2.Insert(), t, "error inserting host")
   270  
   271  				host3 := &host.Host{
   272  					Id:        "h3",
   273  					Distro:    distro.Distro{Id: "d2"},
   274  					Status:    evergreen.HostRunning,
   275  					StartedBy: evergreen.User,
   276  					Provider:  mock.ProviderName,
   277  				}
   278  				testutil.HandleTestingErr(host3.Insert(), t, "error inserting host")
   279  
   280  				host4 := &host.Host{
   281  					Id:        "h4",
   282  					Distro:    distro.Distro{Id: "d2"},
   283  					Status:    evergreen.HostRunning,
   284  					StartedBy: evergreen.User,
   285  					Provider:  mock.ProviderName,
   286  				}
   287  				testutil.HandleTestingErr(host4.Insert(), t, "error inserting host")
   288  
   289  				// flag the excess hosts - there should be 2, both from
   290  				// the second distro
   291  				excess, err := flagExcessHosts(distros, nil)
   292  				So(err, ShouldBeNil)
   293  				So(len(excess), ShouldEqual, 2)
   294  				for _, host := range excess {
   295  					So(host.Distro.Id, ShouldEqual, "d2")
   296  				}
   297  
   298  			})
   299  
   300  			Convey("if both distros have excess hosts, the appropriate number"+
   301  				" of hosts from each distro should be flagged", func() {
   302  
   303  				// insert three hosts for each distro
   304  
   305  				host1 := &host.Host{
   306  					Id:        "h1",
   307  					Distro:    distro.Distro{Id: "d1"},
   308  					Status:    evergreen.HostRunning,
   309  					StartedBy: evergreen.User,
   310  					Provider:  mock.ProviderName,
   311  				}
   312  				testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   313  
   314  				host2 := &host.Host{
   315  					Id:        "h2",
   316  					Distro:    distro.Distro{Id: "d1"},
   317  					Status:    evergreen.HostRunning,
   318  					StartedBy: evergreen.User,
   319  					Provider:  mock.ProviderName,
   320  				}
   321  				testutil.HandleTestingErr(host2.Insert(), t, "error inserting host")
   322  
   323  				host3 := &host.Host{
   324  					Id:        "h3",
   325  					Distro:    distro.Distro{Id: "d1"},
   326  					Status:    evergreen.HostRunning,
   327  					StartedBy: evergreen.User,
   328  					Provider:  mock.ProviderName,
   329  				}
   330  				testutil.HandleTestingErr(host3.Insert(), t, "error inserting host")
   331  
   332  				host4 := &host.Host{
   333  					Id:        "h4",
   334  					Distro:    distro.Distro{Id: "d2"},
   335  					Status:    evergreen.HostRunning,
   336  					StartedBy: evergreen.User,
   337  					Provider:  mock.ProviderName,
   338  				}
   339  				testutil.HandleTestingErr(host4.Insert(), t, "error inserting host")
   340  
   341  				host5 := &host.Host{
   342  					Id:        "h5",
   343  					Distro:    distro.Distro{Id: "d2"},
   344  					Status:    evergreen.HostRunning,
   345  					StartedBy: evergreen.User,
   346  					Provider:  mock.ProviderName,
   347  				}
   348  				testutil.HandleTestingErr(host5.Insert(), t, "error inserting host")
   349  
   350  				host6 := &host.Host{
   351  					Id:        "h6",
   352  					Distro:    distro.Distro{Id: "d2"},
   353  					Status:    evergreen.HostRunning,
   354  					StartedBy: evergreen.User,
   355  					Provider:  mock.ProviderName,
   356  				}
   357  				testutil.HandleTestingErr(host6.Insert(), t, "error inserting host")
   358  
   359  				// find the excess hosts - there should be one for the first
   360  				// distro and two for the second
   361  				excess, err := flagExcessHosts(distros, nil)
   362  				So(err, ShouldBeNil)
   363  				So(len(excess), ShouldEqual, 3)
   364  				excessFirst := 0
   365  				excessSecond := 0
   366  				for _, host := range excess {
   367  					if host.Distro.Id == "d1" {
   368  						excessFirst++
   369  					}
   370  					if host.Distro.Id == "d2" {
   371  						excessSecond++
   372  					}
   373  				}
   374  				So(excessFirst, ShouldEqual, 1)
   375  				So(excessSecond, ShouldEqual, 2)
   376  
   377  			})
   378  
   379  			Convey("hosts currently running a task should not be"+
   380  				" flagged", func() {
   381  
   382  				// insert two hosts for each distro, with running tasks
   383  
   384  				host1 := &host.Host{
   385  					Id:          "h1",
   386  					Distro:      distro.Distro{Id: "d1"},
   387  					Status:      evergreen.HostRunning,
   388  					StartedBy:   evergreen.User,
   389  					RunningTask: "t1",
   390  					Provider:    mock.ProviderName,
   391  				}
   392  				testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   393  
   394  				host2 := &host.Host{
   395  					Id:          "h2",
   396  					Distro:      distro.Distro{Id: "d1"},
   397  					Status:      evergreen.HostRunning,
   398  					StartedBy:   evergreen.User,
   399  					RunningTask: "t2",
   400  					Provider:    mock.ProviderName,
   401  				}
   402  				testutil.HandleTestingErr(host2.Insert(), t, "error inserting host")
   403  
   404  				host3 := &host.Host{
   405  					Id:          "h3",
   406  					Distro:      distro.Distro{Id: "d2"},
   407  					Status:      evergreen.HostRunning,
   408  					StartedBy:   evergreen.User,
   409  					RunningTask: "t3",
   410  					Provider:    mock.ProviderName,
   411  				}
   412  				testutil.HandleTestingErr(host3.Insert(), t, "error inserting host")
   413  
   414  				host4 := &host.Host{
   415  					Id:          "h4",
   416  					Distro:      distro.Distro{Id: "d2"},
   417  					Status:      evergreen.HostRunning,
   418  					StartedBy:   evergreen.User,
   419  					RunningTask: "t4",
   420  					Provider:    mock.ProviderName,
   421  				}
   422  				testutil.HandleTestingErr(host4.Insert(), t, "error inserting host")
   423  
   424  				// find the excess hosts - there should be none, since all of
   425  				// the hosts are running tasks and cannot safely be terminated
   426  				excess, err := flagExcessHosts(distros, nil)
   427  				So(err, ShouldBeNil)
   428  				So(len(excess), ShouldEqual, 0)
   429  
   430  			})
   431  
   432  		})
   433  
   434  	})
   435  
   436  }
   437  
   438  func TestFlaggingUnprovisionedHosts(t *testing.T) {
   439  
   440  	testConfig := testutil.TestConfig()
   441  
   442  	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testConfig))
   443  
   444  	Convey("When flagging unprovisioned hosts to be terminated", t, func() {
   445  
   446  		// reset the db
   447  		testutil.HandleTestingErr(db.ClearCollections(host.Collection),
   448  			t, "error clearing hosts collection")
   449  
   450  		Convey("hosts that have not hit the provisioning limit should"+
   451  			" be ignored", func() {
   452  
   453  			host1 := &host.Host{
   454  				Id:           "h1",
   455  				StartedBy:    evergreen.User,
   456  				CreationTime: time.Now().Add(-time.Minute * 10),
   457  			}
   458  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   459  
   460  			unprovisioned, err := flagUnprovisionedHosts(nil, nil)
   461  			So(err, ShouldBeNil)
   462  			So(len(unprovisioned), ShouldEqual, 0)
   463  
   464  		})
   465  
   466  		Convey("hosts that are already terminated should be ignored", func() {
   467  
   468  			host1 := &host.Host{
   469  				Id:           "h1",
   470  				StartedBy:    evergreen.User,
   471  				CreationTime: time.Now().Add(-time.Minute * 40),
   472  				Status:       evergreen.HostTerminated,
   473  			}
   474  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   475  
   476  			unprovisioned, err := flagUnprovisionedHosts(nil, nil)
   477  			So(err, ShouldBeNil)
   478  			So(len(unprovisioned), ShouldEqual, 0)
   479  
   480  		})
   481  
   482  		Convey("hosts that are already provisioned should be ignored", func() {
   483  
   484  			host1 := &host.Host{
   485  				Id:           "h1",
   486  				StartedBy:    evergreen.User,
   487  				CreationTime: time.Now().Add(-time.Minute * 40),
   488  				Provisioned:  true,
   489  			}
   490  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   491  
   492  			unprovisioned, err := flagUnprovisionedHosts(nil, nil)
   493  			So(err, ShouldBeNil)
   494  			So(len(unprovisioned), ShouldEqual, 0)
   495  
   496  		})
   497  
   498  		Convey("hosts that have hit the provisioning limit should be"+
   499  			" flagged", func() {
   500  
   501  			host1 := &host.Host{
   502  				Id:           "h1",
   503  				StartedBy:    evergreen.User,
   504  				CreationTime: time.Now().Add(-time.Minute * 40),
   505  			}
   506  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   507  
   508  			unprovisioned, err := flagUnprovisionedHosts(nil, nil)
   509  			So(err, ShouldBeNil)
   510  			So(len(unprovisioned), ShouldEqual, 1)
   511  			So(unprovisioned[0].Id, ShouldEqual, "h1")
   512  
   513  		})
   514  
   515  	})
   516  }
   517  
   518  func TestFlaggingProvisioningFailedHosts(t *testing.T) {
   519  
   520  	testConfig := testutil.TestConfig()
   521  
   522  	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testConfig))
   523  
   524  	Convey("When flagging hosts whose provisioning failed", t, func() {
   525  
   526  		// reset the db
   527  		testutil.HandleTestingErr(db.ClearCollections(host.Collection),
   528  			t, "error clearing hosts collection")
   529  
   530  		Convey("only hosts whose provisioning failed should be"+
   531  			" picked up", func() {
   532  
   533  			host1 := &host.Host{
   534  				Id:     "h1",
   535  				Status: evergreen.HostRunning,
   536  			}
   537  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   538  
   539  			host2 := &host.Host{
   540  				Id:     "h2",
   541  				Status: evergreen.HostUninitialized,
   542  			}
   543  			testutil.HandleTestingErr(host2.Insert(), t, "error inserting host")
   544  
   545  			host3 := &host.Host{
   546  				Id:     "h3",
   547  				Status: evergreen.HostProvisionFailed,
   548  			}
   549  			testutil.HandleTestingErr(host3.Insert(), t, "error inserting host")
   550  
   551  			unprovisioned, err := flagProvisioningFailedHosts(nil, nil)
   552  			So(err, ShouldBeNil)
   553  			So(len(unprovisioned), ShouldEqual, 1)
   554  			So(unprovisioned[0].Id, ShouldEqual, "h3")
   555  
   556  		})
   557  
   558  	})
   559  }
   560  
   561  func TestFlaggingExpiredHosts(t *testing.T) {
   562  
   563  	testConfig := testutil.TestConfig()
   564  
   565  	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testConfig))
   566  
   567  	Convey("When flagging expired hosts to be terminated", t, func() {
   568  
   569  		// reset the db
   570  		testutil.HandleTestingErr(db.ClearCollections(host.Collection),
   571  			t, "error clearing hosts collection")
   572  
   573  		Convey("hosts started by the default user should be filtered"+
   574  			" out", func() {
   575  
   576  			host1 := &host.Host{
   577  				Id:        "h1",
   578  				Status:    evergreen.HostRunning,
   579  				StartedBy: evergreen.User,
   580  			}
   581  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   582  
   583  			expired, err := flagExpiredHosts(nil, nil)
   584  			So(err, ShouldBeNil)
   585  			So(len(expired), ShouldEqual, 0)
   586  
   587  		})
   588  
   589  		Convey("hosts that are terminated or quarantined should be filtered"+
   590  			" out", func() {
   591  
   592  			host1 := &host.Host{
   593  				Id:     "h1",
   594  				Status: evergreen.HostQuarantined,
   595  			}
   596  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   597  
   598  			host2 := &host.Host{
   599  				Id:     "h2",
   600  				Status: evergreen.HostTerminated,
   601  			}
   602  			testutil.HandleTestingErr(host2.Insert(), t, "error inserting host")
   603  
   604  			expired, err := flagExpiredHosts(nil, nil)
   605  			So(err, ShouldBeNil)
   606  			So(len(expired), ShouldEqual, 0)
   607  
   608  		})
   609  
   610  		Convey("hosts should be returned if their expiration threshold has"+
   611  			" been reached", func() {
   612  
   613  			// not expired
   614  			host1 := &host.Host{
   615  				Id:             "h1",
   616  				Status:         evergreen.HostRunning,
   617  				ExpirationTime: time.Now().Add(time.Minute * 10),
   618  			}
   619  			testutil.HandleTestingErr(host1.Insert(), t, "error inserting host")
   620  
   621  			// expired
   622  			host2 := &host.Host{
   623  				Id:             "h2",
   624  				Status:         evergreen.HostRunning,
   625  				ExpirationTime: time.Now().Add(-time.Minute * 10),
   626  			}
   627  			testutil.HandleTestingErr(host2.Insert(), t, "error inserting host")
   628  
   629  			expired, err := flagExpiredHosts(nil, nil)
   630  			So(err, ShouldBeNil)
   631  			So(len(expired), ShouldEqual, 1)
   632  			So(expired[0].Id, ShouldEqual, "h2")
   633  
   634  		})
   635  
   636  	})
   637  
   638  }