github.com/hashicorp/vault/sdk@v0.11.0/helper/clientcountutil/clientcountutil_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package clientcountutil
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"io"
    10  	"net/http"
    11  	"net/http/httptest"
    12  	"testing"
    13  
    14  	"github.com/hashicorp/vault/api"
    15  	"github.com/hashicorp/vault/sdk/helper/clientcountutil/generation"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  // TestNewCurrentMonthData verifies that current month is set correctly and that
    20  // there are no open segments
    21  func TestNewCurrentMonthData(t *testing.T) {
    22  	generator := NewActivityLogData(nil).NewCurrentMonthData()
    23  	require.True(t, generator.data.Data[0].GetCurrentMonth())
    24  	require.True(t, generator.addingToMonth.GetCurrentMonth())
    25  	require.Nil(t, generator.addingToSegment)
    26  }
    27  
    28  // TestNewMonthDataMonthsAgo verifies that months ago is set correctly and that
    29  // there are no open segments
    30  func TestNewMonthDataMonthsAgo(t *testing.T) {
    31  	generator := NewActivityLogData(nil).NewPreviousMonthData(3)
    32  	require.Equal(t, int32(3), generator.data.Data[0].GetMonthsAgo())
    33  	require.Equal(t, int32(3), generator.addingToMonth.GetMonthsAgo())
    34  	require.Nil(t, generator.addingToSegment)
    35  }
    36  
    37  // TestNewMonthData_MultipleMonths opens a month 3 months ago then 2 months ago.
    38  // The test verifies that the generator is set to add to the correct month. We
    39  // then open a current month, and verify that the generator will add to the
    40  // current month.
    41  func TestNewMonthData_MultipleMonths(t *testing.T) {
    42  	generator := NewActivityLogData(nil).NewPreviousMonthData(3).NewPreviousMonthData(2)
    43  	require.Equal(t, int32(2), generator.data.Data[1].GetMonthsAgo())
    44  	require.Equal(t, int32(2), generator.addingToMonth.GetMonthsAgo())
    45  	generator = generator.NewCurrentMonthData()
    46  	require.True(t, generator.data.Data[2].GetCurrentMonth())
    47  	require.True(t, generator.addingToMonth.GetCurrentMonth())
    48  }
    49  
    50  // TestNewCurrentMonthData_ClientsSeen calls ClientsSeen with 3 clients, and
    51  // verifies that they are added to the input data
    52  func TestNewCurrentMonthData_ClientsSeen(t *testing.T) {
    53  	wantClients := []*generation.Client{
    54  		{
    55  			Id:         "1",
    56  			Namespace:  "ns",
    57  			Mount:      "mount",
    58  			ClientType: "non-entity",
    59  		},
    60  		{
    61  			Id: "2",
    62  		},
    63  		{
    64  			Id:    "3",
    65  			Count: int32(3),
    66  		},
    67  	}
    68  	generator := NewActivityLogData(nil).NewCurrentMonthData().ClientsSeen(wantClients...)
    69  	require.Equal(t, generator.data.Data[0].GetAll().Clients, wantClients)
    70  	require.True(t, generator.data.Data[0].GetCurrentMonth())
    71  }
    72  
    73  // TestSegment_AddClients adds clients in a variety of ways to an open segment
    74  // and verifies that the clients are present in the segment with the correct
    75  // options
    76  func TestSegment_AddClients(t *testing.T) {
    77  	testAddClients(t, func() *ActivityLogDataGenerator {
    78  		return NewActivityLogData(nil).NewCurrentMonthData().Segment()
    79  	}, func(g *ActivityLogDataGenerator) *generation.Client {
    80  		return g.data.Data[0].GetSegments().Segments[0].Clients.Clients[0]
    81  	})
    82  }
    83  
    84  // TestSegment_MultipleSegments opens a current month and adds a client to an
    85  // un-indexed segment, then opens an indexed segment and adds a client. The test
    86  // verifies that clients are present in both segments, and that the segment
    87  // index is correctly recorded
    88  func TestSegment_MultipleSegments(t *testing.T) {
    89  	generator := NewActivityLogData(nil).NewCurrentMonthData().Segment().NewClientSeen().Segment(WithSegmentIndex(2)).NewClientSeen()
    90  	require.Len(t, generator.data.Data[0].GetSegments().Segments[0].Clients.Clients, 1)
    91  	require.Len(t, generator.data.Data[0].GetSegments().Segments[1].Clients.Clients, 1)
    92  	require.Equal(t, int32(2), *generator.data.Data[0].GetSegments().Segments[1].SegmentIndex)
    93  	require.Equal(t, int32(2), *generator.addingToSegment.SegmentIndex)
    94  }
    95  
    96  // TestSegment_NewMonth adds a client to a segment, then starts a new month. The
    97  // test verifies that there are no open segments
    98  func TestSegment_NewMonth(t *testing.T) {
    99  	generator := NewActivityLogData(nil).NewCurrentMonthData().Segment().NewClientSeen().NewPreviousMonthData(1)
   100  	require.Nil(t, generator.addingToSegment)
   101  }
   102  
   103  // TestNewCurrentMonthData_AddClients adds clients in a variety of ways to an
   104  // the current month and verifies that the clients are present in the month with
   105  // the correct options
   106  func TestNewCurrentMonthData_AddClients(t *testing.T) {
   107  	testAddClients(t, func() *ActivityLogDataGenerator {
   108  		return NewActivityLogData(nil).NewCurrentMonthData()
   109  	}, func(g *ActivityLogDataGenerator) *generation.Client {
   110  		return g.data.Data[0].GetAll().Clients[0]
   111  	})
   112  }
   113  
   114  // TestWrite creates a mock http server and writes generated data to it. The
   115  // test verifies that the returned paths are parsed correctly, and that the JSON
   116  // sent to the server is correct.
   117  func TestWrite(t *testing.T) {
   118  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   119  		_, err := io.WriteString(w, `{"data":{"paths":["path1","path2"]}}`)
   120  		require.NoError(t, err)
   121  		body, err := io.ReadAll(r.Body)
   122  		require.NoError(t, err)
   123  		raw := map[string]string{}
   124  		err = json.Unmarshal(body, &raw)
   125  		require.NoError(t, err)
   126  		require.JSONEq(t, `{"write":["WRITE_ENTITIES"],"data":[{"monthsAgo":3,"all":{"clients":[{"count":1}]}},{"monthsAgo":2,"segments":{"segments":[{"segmentIndex":2,"clients":{"clients":[{"count":1,"repeated":true}]}}]}},{"currentMonth":true}]}`, raw["input"])
   127  	}))
   128  	defer ts.Close()
   129  
   130  	client, err := api.NewClient(&api.Config{
   131  		Address: ts.URL,
   132  	})
   133  	require.NoError(t, err)
   134  	paths, err := NewActivityLogData(client).
   135  		NewPreviousMonthData(3).
   136  		NewClientSeen().
   137  		NewPreviousMonthData(2).
   138  		Segment(WithSegmentIndex(2)).
   139  		RepeatedClientSeen().
   140  		NewCurrentMonthData().Write(context.Background(), generation.WriteOptions_WRITE_ENTITIES)
   141  
   142  	require.NoError(t, err)
   143  	require.Equal(t, []string{"path1", "path2"}, paths)
   144  }
   145  
   146  func testAddClients(t *testing.T, makeGenerator func() *ActivityLogDataGenerator, getClient func(data *ActivityLogDataGenerator) *generation.Client) {
   147  	t.Helper()
   148  	clientOptions := []ClientOption{
   149  		WithClientNamespace("ns"), WithClientMount("mount"), WithClientIsNonEntity(), WithClientID("1"),
   150  	}
   151  	generator := makeGenerator().NewClientSeen(clientOptions...)
   152  	require.Equal(t, getClient(generator), &generation.Client{
   153  		Id:         "1",
   154  		Count:      1,
   155  		Namespace:  "ns",
   156  		Mount:      "mount",
   157  		ClientType: "non-entity",
   158  	})
   159  
   160  	generator = makeGenerator().NewClientsSeen(4, clientOptions...)
   161  	require.Equal(t, getClient(generator), &generation.Client{
   162  		Id:         "1",
   163  		Count:      4,
   164  		Namespace:  "ns",
   165  		Mount:      "mount",
   166  		ClientType: "non-entity",
   167  	})
   168  
   169  	generator = makeGenerator().RepeatedClientSeen(clientOptions...)
   170  	require.Equal(t, getClient(generator), &generation.Client{
   171  		Id:         "1",
   172  		Count:      1,
   173  		Repeated:   true,
   174  		Namespace:  "ns",
   175  		Mount:      "mount",
   176  		ClientType: "non-entity",
   177  	})
   178  
   179  	generator = makeGenerator().RepeatedClientsSeen(4, clientOptions...)
   180  	require.Equal(t, getClient(generator), &generation.Client{
   181  		Id:         "1",
   182  		Count:      4,
   183  		Repeated:   true,
   184  		Namespace:  "ns",
   185  		Mount:      "mount",
   186  		ClientType: "non-entity",
   187  	})
   188  
   189  	generator = makeGenerator().RepeatedClientSeenFromMonthsAgo(3, clientOptions...)
   190  	require.Equal(t, getClient(generator), &generation.Client{
   191  		Id:                "1",
   192  		Count:             1,
   193  		RepeatedFromMonth: 3,
   194  		Namespace:         "ns",
   195  		Mount:             "mount",
   196  		ClientType:        "non-entity",
   197  	})
   198  
   199  	generator = makeGenerator().RepeatedClientsSeenFromMonthsAgo(4, 3, clientOptions...)
   200  	require.Equal(t, getClient(generator), &generation.Client{
   201  		Id:                "1",
   202  		Count:             4,
   203  		RepeatedFromMonth: 3,
   204  		Namespace:         "ns",
   205  		Mount:             "mount",
   206  		ClientType:        "non-entity",
   207  	})
   208  }
   209  
   210  // TestSetMonthOptions sets month options and verifies that they are saved
   211  func TestSetMonthOptions(t *testing.T) {
   212  	generator := NewActivityLogData(nil).NewCurrentMonthData().SetMonthOptions(WithEmptySegmentIndexes(3, 4),
   213  		WithMaximumSegmentIndex(7), WithSkipSegmentIndexes(1, 2))
   214  	require.Equal(t, int32(7), generator.data.Data[0].NumSegments)
   215  	require.Equal(t, []int32{3, 4}, generator.data.Data[0].EmptySegmentIndexes)
   216  	require.Equal(t, []int32{1, 2}, generator.data.Data[0].SkipSegmentIndexes)
   217  }
   218  
   219  // TestVerifyInput constructs invalid inputs and ensures that VerifyInput
   220  // returns an error
   221  func TestVerifyInput(t *testing.T) {
   222  	cases := []struct {
   223  		name      string
   224  		generator *ActivityLogDataGenerator
   225  	}{
   226  		{
   227  			name: "repeated client with only 1 month",
   228  			generator: NewActivityLogData(nil).
   229  				NewCurrentMonthData().
   230  				RepeatedClientSeen(),
   231  		},
   232  		{
   233  			name: "repeated client with segment",
   234  			generator: NewActivityLogData(nil).
   235  				NewCurrentMonthData().
   236  				Segment().
   237  				RepeatedClientSeen(),
   238  		},
   239  		{
   240  			name: "repeated client with earliest month",
   241  			generator: NewActivityLogData(nil).
   242  				NewCurrentMonthData().
   243  				NewClientSeen().
   244  				NewPreviousMonthData(2).
   245  				RepeatedClientSeen(),
   246  		},
   247  		{
   248  			name: "repeated month",
   249  			generator: NewActivityLogData(nil).
   250  				NewPreviousMonthData(1).
   251  				NewPreviousMonthData(1),
   252  		},
   253  		{
   254  			name: "repeated current month",
   255  			generator: NewActivityLogData(nil).
   256  				NewCurrentMonthData().
   257  				NewCurrentMonthData(),
   258  		},
   259  		{
   260  			name: "repeated segment index",
   261  			generator: NewActivityLogData(nil).
   262  				NewCurrentMonthData().
   263  				Segment(WithSegmentIndex(1)).
   264  				Segment(WithSegmentIndex(1)),
   265  		},
   266  		{
   267  			name: "segment with num segments",
   268  			generator: NewActivityLogData(nil).
   269  				NewCurrentMonthData().
   270  				Segment().
   271  				SetMonthOptions(WithMaximumSegmentIndex(1)),
   272  		},
   273  	}
   274  	for _, tc := range cases {
   275  		t.Run(tc.name, func(t *testing.T) {
   276  			require.Error(t, VerifyInput(tc.generator.data))
   277  		})
   278  	}
   279  }