github.com/wtsi-ssg/wrstat/v4@v4.5.1/basedirs/history_test.go (about)

     1  /*******************************************************************************
     2   * Copyright (c) 2023 Genome Research Ltd.
     3   *
     4   * Authors:
     5   *   Sendu Bala <sb10@sanger.ac.uk>
     6   *   Michael Woolnough <mw31@sanger.ac.uk>
     7   *
     8   * Permission is hereby granted, free of charge, to any person obtaining
     9   * a copy of this software and associated documentation files (the
    10   * "Software"), to deal in the Software without restriction, including
    11   * without limitation the rights to use, copy, modify, merge, publish,
    12   * distribute, sublicense, and/or sell copies of the Software, and to
    13   * permit persons to whom the Software is furnished to do so, subject to
    14   * the following conditions:
    15   *
    16   * The above copyright notice and this permission notice shall be included
    17   * in all copies or substantial portions of the Software.
    18   *
    19   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    20   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    21   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    22   * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    23   * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    24   * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    25   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    26   ******************************************************************************/
    27  
    28  package basedirs
    29  
    30  import (
    31  	"testing"
    32  	"time"
    33  
    34  	. "github.com/smartystreets/goconvey/convey"
    35  )
    36  
    37  func TestHistory(t *testing.T) {
    38  	now := time.Now()
    39  
    40  	quotaMax := 1000000
    41  	quotaUsageStart := 1
    42  	dy := float64(quotaMax - quotaUsageStart)
    43  	changeDays := float64(2)
    44  	usageFor4Years := changeDays * dy / (4 * 365)
    45  	usageFor6Years := changeDays * dy / (6 * 365)
    46  
    47  	for _, test := range [...]struct {
    48  		Name        string
    49  		Histories   []History
    50  		UntilSize   time.Time
    51  		UntilInodes time.Time
    52  	}{
    53  		{
    54  			Name:        "Zero history produces no dates",
    55  			Histories:   nil,
    56  			UntilSize:   time.Time{},
    57  			UntilInodes: time.Time{},
    58  		},
    59  		{
    60  			Name: "A Single item in History produces no dates",
    61  			Histories: []History{
    62  				{
    63  					Date:        now,
    64  					UsageSize:   2,
    65  					QuotaSize:   10,
    66  					UsageInodes: 1,
    67  					QuotaInodes: 20,
    68  				},
    69  			},
    70  			UntilSize:   time.Time{},
    71  			UntilInodes: time.Time{},
    72  		},
    73  		{
    74  			Name: "A Single item in History, with Quotas full produces now",
    75  			Histories: []History{
    76  				{
    77  					Date:        now,
    78  					UsageSize:   10,
    79  					QuotaSize:   10,
    80  					UsageInodes: 20,
    81  					QuotaInodes: 20,
    82  				},
    83  			},
    84  			UntilSize:   now,
    85  			UntilInodes: now,
    86  		},
    87  		{
    88  			Name: "A Single item in History, with Quotas over-full produces now",
    89  			Histories: []History{
    90  				{
    91  					Date:        now,
    92  					UsageSize:   20,
    93  					QuotaSize:   10,
    94  					UsageInodes: 30,
    95  					QuotaInodes: 20,
    96  				},
    97  			},
    98  			UntilSize:   now,
    99  			UntilInodes: now,
   100  		},
   101  		{
   102  			Name: "Two items in History produces useful predicted dates",
   103  			Histories: []History{
   104  				{
   105  					Date:        now.Add(-24 * time.Hour),
   106  					UsageSize:   5,
   107  					QuotaSize:   100,
   108  					UsageInodes: 0,
   109  					QuotaInodes: 20,
   110  				},
   111  				{
   112  					Date:        now,
   113  					UsageSize:   20,
   114  					QuotaSize:   100,
   115  					UsageInodes: 10,
   116  					QuotaInodes: 20,
   117  				},
   118  			},
   119  			UntilSize:   now.Add(secondsInDay*5 + 8*time.Hour),
   120  			UntilInodes: now.Add(secondsInDay * 1),
   121  		},
   122  		{
   123  			Name: "Two items in history, with no change in size, and inodes at quota" +
   124  				" produces no date for size and now for inodes",
   125  			Histories: []History{
   126  				{
   127  					Date:        time.Now().Add(-25 * time.Hour),
   128  					UsageSize:   5,
   129  					QuotaSize:   100,
   130  					UsageInodes: 0,
   131  					QuotaInodes: 20,
   132  				},
   133  				{
   134  					Date:        time.Now(),
   135  					UsageSize:   5,
   136  					QuotaSize:   100,
   137  					UsageInodes: 20,
   138  					QuotaInodes: 20,
   139  				},
   140  			},
   141  			UntilSize:   time.Time{},
   142  			UntilInodes: now,
   143  		},
   144  		{
   145  			Name: "Two items in history, with a downward trend for size and inodes, produces no dates",
   146  			Histories: []History{
   147  				{
   148  					Date:        time.Now().Add(-24 * time.Hour),
   149  					UsageSize:   50,
   150  					QuotaSize:   100,
   151  					UsageInodes: 50,
   152  					QuotaInodes: 20,
   153  				},
   154  				{
   155  					Date:        time.Now(),
   156  					UsageSize:   10,
   157  					QuotaSize:   100,
   158  					UsageInodes: 0,
   159  					QuotaInodes: 20,
   160  				},
   161  			},
   162  			UntilSize:   time.Time{},
   163  			UntilInodes: time.Time{},
   164  		},
   165  		{
   166  			Name: "Three items in history correctly uses the last and third from last items to predict dates.",
   167  			Histories: []History{
   168  				{
   169  					Date:        time.Now().Add(-48 * time.Hour),
   170  					UsageSize:   0,
   171  					QuotaSize:   100,
   172  					UsageInodes: 0,
   173  					QuotaInodes: 20,
   174  				},
   175  				{
   176  					Date:        time.Now().Add(-24 * time.Hour),
   177  					UsageSize:   5,
   178  					QuotaSize:   100,
   179  					UsageInodes: 5,
   180  					QuotaInodes: 20,
   181  				},
   182  				{
   183  					Date:        time.Now(),
   184  					UsageSize:   5,
   185  					QuotaSize:   100,
   186  					UsageInodes: 10,
   187  					QuotaInodes: 20,
   188  				},
   189  			},
   190  			UntilSize:   now.Add(secondsInDay * 38),
   191  			UntilInodes: now.Add(secondsInDay * 2),
   192  		},
   193  		{
   194  			Name: "Four items in history correctly uses the last and third from last items to predict dates.",
   195  			Histories: []History{
   196  				{
   197  					Date:        time.Now().Add(-72 * time.Hour),
   198  					UsageSize:   100,
   199  					QuotaSize:   100,
   200  					UsageInodes: 100,
   201  					QuotaInodes: 20,
   202  				},
   203  				{
   204  					Date:        time.Now().Add(-48 * time.Hour),
   205  					UsageSize:   0,
   206  					QuotaSize:   100,
   207  					UsageInodes: 0,
   208  					QuotaInodes: 20,
   209  				},
   210  				{
   211  					Date:        time.Now().Add(-24 * time.Hour),
   212  					UsageSize:   5,
   213  					QuotaSize:   100,
   214  					UsageInodes: 5,
   215  					QuotaInodes: 20,
   216  				},
   217  				{
   218  					Date:        time.Now(),
   219  					UsageSize:   5,
   220  					QuotaSize:   100,
   221  					UsageInodes: 10,
   222  					QuotaInodes: 20,
   223  				},
   224  			},
   225  			UntilSize:   now.Add(secondsInDay * 38),
   226  			UntilInodes: now.Add(secondsInDay * 2),
   227  		},
   228  		{
   229  			Name: "Predictions beyond 5 years are treated as not running out.",
   230  			Histories: []History{
   231  				{
   232  					Date:        time.Now().Add(-(time.Duration(changeDays * 24)) * time.Hour),
   233  					UsageSize:   uint64(quotaUsageStart),
   234  					QuotaSize:   uint64(quotaMax),
   235  					UsageInodes: uint64(quotaUsageStart),
   236  					QuotaInodes: uint64(quotaMax),
   237  				},
   238  				{
   239  					Date:        time.Now().Add(-24 * time.Hour),
   240  					UsageSize:   uint64(quotaUsageStart),
   241  					QuotaSize:   uint64(quotaMax),
   242  					UsageInodes: uint64(quotaUsageStart),
   243  					QuotaInodes: uint64(quotaMax),
   244  				},
   245  				{
   246  					Date:        time.Now(),
   247  					UsageSize:   uint64(usageFor6Years),
   248  					QuotaSize:   uint64(quotaMax),
   249  					UsageInodes: uint64(usageFor4Years),
   250  					QuotaInodes: uint64(quotaMax),
   251  				},
   252  			},
   253  			UntilSize:   time.Time{},
   254  			UntilInodes: now.Add(secondsInDay * 4 * 365),
   255  		},
   256  	} {
   257  		Convey(test.Name, t, func() {
   258  			untilSize, untilInodes := DateQuotaFull(test.Histories)
   259  
   260  			marginOfError := int64(2)
   261  
   262  			if time.Until(untilInodes) > 3*365*24*time.Hour {
   263  				marginOfError = 15000
   264  			}
   265  
   266  			So(untilSize.Unix(), ShouldBeBetween, test.UntilSize.Unix()-marginOfError, test.UntilSize.Unix()+marginOfError)
   267  			So(untilInodes.Unix(), ShouldBeBetween, test.UntilInodes.Unix()-marginOfError, test.UntilInodes.Unix()+marginOfError)
   268  		})
   269  	}
   270  }