github.com/influxdata/influxdb/v2@v2.7.6/annotation_test.go (about)

     1  package influxdb
     2  
     3  import (
     4  	"encoding/json"
     5  	"strings"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/influxdata/influxdb/v2/kit/platform"
    10  	"github.com/influxdata/influxdb/v2/kit/platform/errors"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  var (
    15  	testTime  time.Time = time.Now()
    16  	testTime2 time.Time = testTime.Add(time.Minute)
    17  
    18  	annID, _ = platform.IDFromString("2345678901234567")
    19  )
    20  
    21  func nowFunc() time.Time {
    22  	return testTime
    23  }
    24  
    25  func TestAnnotationCreate(t *testing.T) {
    26  	type tst struct {
    27  		name     string
    28  		input    AnnotationCreate
    29  		expected AnnotationCreate
    30  		err      *errors.Error
    31  	}
    32  
    33  	tests := []tst{
    34  		{
    35  			name: "minimum valid create request",
    36  			input: AnnotationCreate{
    37  				Summary: "this is a default annotation",
    38  			},
    39  			expected: AnnotationCreate{
    40  				StreamTag: "default",
    41  				Summary:   "this is a default annotation",
    42  				EndTime:   &testTime,
    43  				StartTime: &testTime,
    44  			},
    45  		},
    46  		{
    47  			name: "full valid create request",
    48  			input: AnnotationCreate{
    49  				StreamTag: "other",
    50  				Summary:   "this is another annotation",
    51  				Message:   "This is a much longer description or message to add to the annotation summary",
    52  				Stickers:  map[string]string{"product": "cloud"},
    53  				EndTime:   &testTime2,
    54  				StartTime: &testTime,
    55  			},
    56  			expected: AnnotationCreate{
    57  				StreamTag: "other",
    58  				Summary:   "this is another annotation",
    59  				Message:   "This is a much longer description or message to add to the annotation summary",
    60  				Stickers:  map[string]string{"product": "cloud"},
    61  				EndTime:   &testTime2,
    62  				StartTime: &testTime,
    63  			},
    64  		},
    65  		{
    66  			name:  "empty create request",
    67  			input: AnnotationCreate{},
    68  			err:   errEmptySummary,
    69  		},
    70  		{
    71  			name: "end time before start create request",
    72  			input: AnnotationCreate{
    73  				Summary:   "this is a default annotation",
    74  				EndTime:   &testTime,
    75  				StartTime: &testTime2,
    76  			},
    77  			err: errReversedTimes,
    78  		},
    79  		{
    80  			name: "default end time before start create request",
    81  			input: AnnotationCreate{
    82  				Summary:   "this is a default annotation",
    83  				StartTime: &testTime2,
    84  			},
    85  			err: errReversedTimes,
    86  		},
    87  		{
    88  			name: "summary too long",
    89  			input: AnnotationCreate{
    90  				Summary: strings.Repeat("a", 256),
    91  			},
    92  			err: errSummaryTooLong,
    93  		},
    94  		{
    95  			name: "message too long",
    96  			input: AnnotationCreate{
    97  				Summary: "longTom",
    98  				Message: strings.Repeat("a", 4097),
    99  			},
   100  			err: errMsgTooLong,
   101  		},
   102  		{
   103  			name: "stream tag too long",
   104  			input: AnnotationCreate{
   105  				Summary:   "longTom",
   106  				StreamTag: strings.Repeat("a", 256),
   107  			},
   108  			err: errStreamTagTooLong,
   109  		},
   110  		{
   111  			name: "sticker key too long",
   112  			input: AnnotationCreate{
   113  				Summary:  "longTom",
   114  				Stickers: map[string]string{strings.Repeat("1", 256): "val"},
   115  			},
   116  			err: errStickerTooLong,
   117  		},
   118  		{
   119  			name: "sticker val too long",
   120  			input: AnnotationCreate{
   121  				Summary:  "longTom",
   122  				Stickers: map[string]string{"key": strings.Repeat("1", 256)},
   123  			},
   124  			err: errStickerTooLong,
   125  		},
   126  	}
   127  
   128  	for _, test := range tests {
   129  		t.Run(test.name, func(t *testing.T) {
   130  			err := test.input.Validate(nowFunc)
   131  			if test.err != nil {
   132  				require.Equal(t, test.err, err)
   133  				return
   134  			}
   135  
   136  			require.NoError(t, err)
   137  			require.Equal(t, test.expected, test.input)
   138  		})
   139  	}
   140  }
   141  
   142  func TestDeleteFilter(t *testing.T) {
   143  	type tst struct {
   144  		name     string
   145  		input    AnnotationDeleteFilter
   146  		expected AnnotationDeleteFilter
   147  		err      *errors.Error
   148  	}
   149  
   150  	tests := []tst{
   151  		{
   152  			name: "minimum valid delete",
   153  			input: AnnotationDeleteFilter{
   154  				StreamTag: "default",
   155  				EndTime:   &testTime,
   156  				StartTime: &testTime,
   157  			},
   158  			expected: AnnotationDeleteFilter{
   159  				StreamTag: "default",
   160  				EndTime:   &testTime,
   161  				StartTime: &testTime,
   162  			},
   163  		},
   164  		{
   165  			name: "full valid delete",
   166  			input: AnnotationDeleteFilter{
   167  				StreamTag: "default",
   168  				Stickers:  map[string]string{"product": "oss"},
   169  				EndTime:   &testTime,
   170  				StartTime: &testTime,
   171  			},
   172  			expected: AnnotationDeleteFilter{
   173  				StreamTag: "default",
   174  				Stickers:  map[string]string{"product": "oss"},
   175  				EndTime:   &testTime,
   176  				StartTime: &testTime,
   177  			},
   178  		},
   179  		{
   180  			name: "missing stream tag",
   181  			input: AnnotationDeleteFilter{
   182  				Stickers:  map[string]string{"product": "oss"},
   183  				EndTime:   &testTime,
   184  				StartTime: &testTime,
   185  			},
   186  			err: errMissingStreamTagOrId,
   187  		},
   188  		{
   189  			name: "missing start time",
   190  			input: AnnotationDeleteFilter{
   191  				StreamTag: "default",
   192  				Stickers:  map[string]string{"product": "oss"},
   193  				EndTime:   &testTime,
   194  			},
   195  			err: errMissingStartTime,
   196  		},
   197  		{
   198  			name: "missing end time",
   199  			input: AnnotationDeleteFilter{
   200  				StreamTag: "default",
   201  				Stickers:  map[string]string{"product": "oss"},
   202  				StartTime: &testTime,
   203  			},
   204  			err: errMissingEndTime,
   205  		},
   206  		{
   207  			name: "end time before start create request",
   208  			input: AnnotationDeleteFilter{
   209  				StreamTag: "default",
   210  				Stickers:  map[string]string{"product": "oss"},
   211  				EndTime:   &testTime,
   212  				StartTime: &testTime2,
   213  			},
   214  			err: errReversedTimes,
   215  		},
   216  	}
   217  
   218  	for _, test := range tests {
   219  		t.Run(test.name, func(t *testing.T) {
   220  			err := test.input.Validate()
   221  			if test.err != nil {
   222  				require.Equal(t, test.err, err)
   223  				return
   224  			}
   225  
   226  			require.NoError(t, err)
   227  			require.Equal(t, test.expected, test.input)
   228  		})
   229  	}
   230  }
   231  
   232  func TestAnnotationListFilter(t *testing.T) {
   233  	type tst struct {
   234  		name       string
   235  		input      AnnotationListFilter
   236  		expected   AnnotationListFilter
   237  		checkValue bool
   238  		err        *errors.Error
   239  	}
   240  
   241  	tests := []tst{
   242  		{
   243  			name: "minimum valid",
   244  			input: AnnotationListFilter{
   245  				BasicFilter: BasicFilter{
   246  					EndTime:   &testTime,
   247  					StartTime: &testTime,
   248  				},
   249  			},
   250  			expected: AnnotationListFilter{
   251  				BasicFilter: BasicFilter{
   252  					EndTime:   &testTime,
   253  					StartTime: &testTime,
   254  				},
   255  			},
   256  		},
   257  		{
   258  			name:  "empty valid",
   259  			input: AnnotationListFilter{},
   260  			expected: AnnotationListFilter{
   261  				BasicFilter: BasicFilter{
   262  					EndTime:   &testTime,
   263  					StartTime: &testTime,
   264  				},
   265  			},
   266  			checkValue: true,
   267  		},
   268  		{
   269  			name: "invalid due to reversed times",
   270  			input: AnnotationListFilter{
   271  				BasicFilter: BasicFilter{
   272  					EndTime:   &testTime,
   273  					StartTime: &testTime2,
   274  				},
   275  			},
   276  			err: errReversedTimes,
   277  		},
   278  	}
   279  
   280  	for _, test := range tests {
   281  		t.Run(test.name, func(t *testing.T) {
   282  			err := test.input.Validate(nowFunc)
   283  			if test.err != nil {
   284  				require.Equal(t, test.err, err)
   285  				return
   286  			}
   287  
   288  			require.NoError(t, err)
   289  			if test.checkValue {
   290  				require.Equal(t, *test.expected.BasicFilter.StartTime, *test.expected.BasicFilter.EndTime)
   291  			} else {
   292  				require.Equal(t, test.expected, test.input)
   293  			}
   294  		})
   295  	}
   296  }
   297  
   298  func TestStreamListFilter(t *testing.T) {
   299  	type tst struct {
   300  		name       string
   301  		input      StreamListFilter
   302  		expected   StreamListFilter
   303  		checkValue bool
   304  		err        *errors.Error
   305  	}
   306  
   307  	tests := []tst{
   308  		{
   309  			name: "minimum valid",
   310  			input: StreamListFilter{
   311  				BasicFilter: BasicFilter{
   312  					EndTime:   &testTime,
   313  					StartTime: &testTime,
   314  				},
   315  			},
   316  			expected: StreamListFilter{
   317  				BasicFilter: BasicFilter{
   318  					EndTime:   &testTime,
   319  					StartTime: &testTime,
   320  				},
   321  			},
   322  		},
   323  		{
   324  			name:  "empty valid",
   325  			input: StreamListFilter{},
   326  			expected: StreamListFilter{
   327  				BasicFilter: BasicFilter{
   328  					EndTime:   &testTime,
   329  					StartTime: &testTime,
   330  				},
   331  			},
   332  			checkValue: true,
   333  		},
   334  		{
   335  			name: "invalid due to reversed times",
   336  			input: StreamListFilter{
   337  				BasicFilter: BasicFilter{
   338  					EndTime:   &testTime,
   339  					StartTime: &testTime2,
   340  				},
   341  			},
   342  			err: errReversedTimes,
   343  		},
   344  	}
   345  
   346  	for _, test := range tests {
   347  		t.Run(test.name, func(t *testing.T) {
   348  			err := test.input.Validate(nowFunc)
   349  			if test.err != nil {
   350  				require.Equal(t, test.err, err)
   351  				return
   352  			}
   353  
   354  			require.NoError(t, err)
   355  			if test.checkValue {
   356  				require.Equal(t, *test.expected.BasicFilter.StartTime, *test.expected.BasicFilter.EndTime)
   357  			} else {
   358  				require.Equal(t, test.expected, test.input)
   359  			}
   360  		})
   361  	}
   362  }
   363  
   364  func TestStreamIsValid(t *testing.T) {
   365  	type tst struct {
   366  		name  string
   367  		input Stream
   368  		err   *errors.Error
   369  	}
   370  
   371  	tests := []tst{
   372  		{
   373  			name: "minimum valid",
   374  			input: Stream{
   375  				Name: "default",
   376  			},
   377  		},
   378  		{
   379  			name:  "empty valid",
   380  			input: Stream{},
   381  		},
   382  		{
   383  			name: "invalid name too long",
   384  			input: Stream{
   385  				Name: strings.Repeat("a", 512),
   386  			},
   387  			err: errStreamNameTooLong,
   388  		},
   389  		{
   390  			name: "invalid description too long",
   391  			input: Stream{
   392  				Name:        "longTom",
   393  				Description: strings.Repeat("a", 2048),
   394  			},
   395  			err: errStreamDescTooLong,
   396  		},
   397  	}
   398  
   399  	for _, test := range tests {
   400  		t.Run(test.name, func(t *testing.T) {
   401  			if test.err != nil {
   402  				require.Equal(t, test.err, test.input.Validate(false))
   403  			} else {
   404  				require.NoError(t, test.input.Validate(false))
   405  			}
   406  		})
   407  	}
   408  }
   409  
   410  func TestBasicStreamIsValid(t *testing.T) {
   411  	type tst struct {
   412  		name     string
   413  		input    BasicStream
   414  		expected bool
   415  	}
   416  
   417  	tests := []tst{
   418  		{
   419  			name: "minimum valid",
   420  			input: BasicStream{
   421  				Names: []string{"default"},
   422  			},
   423  			expected: true,
   424  		},
   425  		{
   426  			name:     "invalid",
   427  			input:    BasicStream{},
   428  			expected: false,
   429  		},
   430  		{
   431  			name:     "empty name",
   432  			input:    BasicStream{Names: []string{""}},
   433  			expected: false,
   434  		},
   435  	}
   436  
   437  	for _, test := range tests {
   438  		t.Run(test.name, func(t *testing.T) {
   439  			require.Equal(t, test.expected, test.input.IsValid())
   440  		})
   441  	}
   442  }
   443  
   444  func TestMashallReadAnnotations(t *testing.T) {
   445  	ra := ReadAnnotations{
   446  		"default": []ReadAnnotation{
   447  			{
   448  				ID:        *annID,
   449  				Summary:   "this is one annotation",
   450  				Stickers:  map[string]string{"env": "testing"},
   451  				StartTime: testTime.Format(time.RFC3339Nano),
   452  				EndTime:   testTime2.Format(time.RFC3339Nano),
   453  			},
   454  			{
   455  				ID:        *annID,
   456  				Summary:   "this is another annotation",
   457  				Stickers:  map[string]string{"env": "testing"},
   458  				StartTime: testTime.Format(time.RFC3339Nano),
   459  				EndTime:   testTime.Format(time.RFC3339Nano),
   460  			},
   461  		},
   462  		"testing": []ReadAnnotation{
   463  			{
   464  				ID:        *annID,
   465  				Summary:   "this is yet another annotation",
   466  				Stickers:  map[string]string{"env": "testing"},
   467  				StartTime: testTime.Format(time.RFC3339Nano),
   468  				EndTime:   testTime.Format(time.RFC3339Nano),
   469  			},
   470  		},
   471  	}
   472  
   473  	b, err := json.Marshal(ra)
   474  	require.NoError(t, err)
   475  	require.Greater(t, len(b), 0)
   476  }
   477  
   478  func TestSetStickerIncludes(t *testing.T) {
   479  	type tst struct {
   480  		name     string
   481  		input    map[string][]string
   482  		expected AnnotationStickers
   483  	}
   484  
   485  	tests := []tst{
   486  		{
   487  			name: "with stickerIncludes",
   488  			input: map[string][]string{
   489  				"stickerIncludes[product]": {"oss"},
   490  				"stickerIncludes[author]":  {"russ"},
   491  				"streams":                  {"default", "blogs"},
   492  			},
   493  			expected: map[string]string{
   494  				"product": "oss",
   495  				"author":  "russ",
   496  			},
   497  		},
   498  		{
   499  			name: "no sticker includes",
   500  			input: map[string][]string{
   501  				"startTime": {"2021-01-13T22%3A17%3A37.953Z"},
   502  				"endTime":   {"2021-01-13T22%3A17%3A37.953Z"},
   503  				"streams":   {"default", "blogs"},
   504  			},
   505  			expected: map[string]string{},
   506  		},
   507  	}
   508  
   509  	for _, test := range tests {
   510  		t.Run(test.name, func(t *testing.T) {
   511  			f := AnnotationListFilter{}
   512  			f.SetStickerIncludes(test.input)
   513  			require.Equal(t, test.expected, f.StickerIncludes)
   514  		})
   515  	}
   516  }
   517  
   518  func TestSetStickers(t *testing.T) {
   519  	type tst struct {
   520  		name     string
   521  		input    map[string][]string
   522  		expected map[string]string
   523  	}
   524  
   525  	tests := []tst{
   526  		{
   527  			name: "with stickers",
   528  			input: map[string][]string{
   529  				"stickers[product]": {"oss"},
   530  				"stickers[author]":  {"russ"},
   531  				"streams":           {"default", "blogs"},
   532  			},
   533  			expected: map[string]string{
   534  				"product": "oss",
   535  				"author":  "russ",
   536  			},
   537  		},
   538  		{
   539  			name: "no stickers",
   540  			input: map[string][]string{
   541  				"startTime": {"2021-01-13T22%3A17%3A37.953Z"},
   542  				"endTime":   {"2021-01-13T22%3A17%3A37.953Z"},
   543  				"streams":   {"default", "blogs"},
   544  			},
   545  			expected: map[string]string{},
   546  		},
   547  	}
   548  
   549  	for _, test := range tests {
   550  		t.Run(test.name, func(t *testing.T) {
   551  			f := AnnotationDeleteFilter{}
   552  			f.SetStickers(test.input)
   553  			require.Equal(t, test.expected, f.Stickers)
   554  		})
   555  	}
   556  }
   557  
   558  func TestStickerSliceToMap(t *testing.T) {
   559  	t.Parallel()
   560  
   561  	tests := []struct {
   562  		name     string
   563  		stickers []string
   564  		want     map[string]string
   565  		wantErr  error
   566  	}{
   567  		{
   568  			"good stickers",
   569  			[]string{"good1=val1", "good2=val2"},
   570  			map[string]string{"good1": "val1", "good2": "val2"},
   571  			nil,
   572  		},
   573  		{
   574  			"bad stickers",
   575  			[]string{"this is an invalid sticker", "shouldbe=likethis"},
   576  			nil,
   577  			invalidStickerError("this is an invalid sticker"),
   578  		},
   579  		{
   580  			"no stickers",
   581  			[]string{},
   582  			map[string]string{},
   583  			nil,
   584  		},
   585  	}
   586  
   587  	for _, tt := range tests {
   588  		got, err := stickerSliceToMap(tt.stickers)
   589  		require.Equal(t, tt.want, got)
   590  		require.Equal(t, tt.wantErr, err)
   591  	}
   592  }