github.com/zorawar87/trillian@v1.2.1/quota/etcd/quotaapi/conversions_test.go (about)

     1  // Copyright 2017 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package quotaapi
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/golang/protobuf/proto"
    21  	"github.com/google/trillian/quota/etcd/quotapb"
    22  	"github.com/google/trillian/quota/etcd/storagepb"
    23  	"github.com/kylelemons/godebug/pretty"
    24  	"google.golang.org/genproto/protobuf/field_mask"
    25  )
    26  
    27  var (
    28  	apiSequencingConfig = &quotapb.Config{
    29  		Name:      "quotas/global/write/config",
    30  		State:     quotapb.Config_ENABLED,
    31  		MaxTokens: 100,
    32  		ReplenishmentStrategy: &quotapb.Config_SequencingBased{
    33  			SequencingBased: &quotapb.SequencingBasedStrategy{},
    34  		},
    35  	}
    36  	apiTimeConfig = &quotapb.Config{
    37  		Name:      "quotas/users/llama/write/config",
    38  		State:     quotapb.Config_DISABLED,
    39  		MaxTokens: 200,
    40  		ReplenishmentStrategy: &quotapb.Config_TimeBased{
    41  			TimeBased: &quotapb.TimeBasedStrategy{
    42  				TokensToReplenish:        10,
    43  				ReplenishIntervalSeconds: 30,
    44  			},
    45  		},
    46  	}
    47  	storageSequencingConfig = &storagepb.Config{
    48  		Name:      apiSequencingConfig.Name,
    49  		State:     storagepb.Config_ENABLED,
    50  		MaxTokens: apiSequencingConfig.MaxTokens,
    51  		ReplenishmentStrategy: &storagepb.Config_SequencingBased{
    52  			SequencingBased: &storagepb.SequencingBasedStrategy{},
    53  		},
    54  	}
    55  	storageTimeConfig = &storagepb.Config{
    56  		Name:      apiTimeConfig.Name,
    57  		State:     storagepb.Config_DISABLED,
    58  		MaxTokens: apiTimeConfig.MaxTokens,
    59  		ReplenishmentStrategy: &storagepb.Config_TimeBased{
    60  			TimeBased: &storagepb.TimeBasedStrategy{
    61  				TokensToReplenish:        apiTimeConfig.GetTimeBased().TokensToReplenish,
    62  				ReplenishIntervalSeconds: apiTimeConfig.GetTimeBased().ReplenishIntervalSeconds,
    63  			},
    64  		},
    65  	}
    66  )
    67  
    68  func TestValidateMask(t *testing.T) {
    69  	tests := []struct {
    70  		desc    string
    71  		mask    *field_mask.FieldMask
    72  		wantErr bool
    73  	}{
    74  		{
    75  			desc: "commonFields",
    76  			mask: commonMask,
    77  		},
    78  		{
    79  			desc: "sequencingBased",
    80  			mask: sequencingBasedMask,
    81  		},
    82  		{
    83  			desc: "timeBased",
    84  			mask: timeBasedMask,
    85  		},
    86  		{
    87  			desc:    "sequencingAndTime",
    88  			mask:    &field_mask.FieldMask{Paths: []string{sequencingBasedPath, timeBasedPath}},
    89  			wantErr: true,
    90  		},
    91  		{
    92  			desc:    "timeAndSequencing",
    93  			mask:    &field_mask.FieldMask{Paths: []string{timeBasedPath, sequencingBasedPath}},
    94  			wantErr: true,
    95  		},
    96  		{
    97  			desc:    "unknownPaths",
    98  			mask:    &field_mask.FieldMask{Paths: []string{statePath, "NOT_A_FIELD", maxTokensPath}},
    99  			wantErr: true,
   100  		},
   101  		{
   102  			desc:    "namePath", // readonly
   103  			mask:    &field_mask.FieldMask{Paths: []string{"name"}},
   104  			wantErr: true,
   105  		},
   106  	}
   107  	for _, test := range tests {
   108  		err := validateMask(test.mask)
   109  		if gotErr := err != nil; gotErr != test.wantErr {
   110  			t.Errorf("%v: validateMask() returned err = %v, wantErr = %v", test.desc, err, test.wantErr)
   111  		}
   112  	}
   113  }
   114  
   115  func TestApplyMask(t *testing.T) {
   116  	// destSequencingConfig must match apiSequencingConfig after the test
   117  	// name is manually copied, as it's a readonly field.
   118  	destSequencingConfig := *storageTimeConfig
   119  	destSequencingConfig.Name = apiSequencingConfig.Name
   120  
   121  	// destTimeConfig must match apiTimeConfig after the test
   122  	destTimeConfig := *storageSequencingConfig
   123  	destTimeConfig.Name = apiTimeConfig.Name
   124  
   125  	destClearSequencing := *storageSequencingConfig
   126  	wantClearSequencing := destClearSequencing
   127  	wantClearSequencing.ReplenishmentStrategy = nil
   128  
   129  	destClearTime := *storageTimeConfig
   130  	wantClearTime := destClearTime
   131  	wantClearTime.ReplenishmentStrategy = nil
   132  
   133  	tests := []struct {
   134  		desc       string
   135  		src        *quotapb.Config
   136  		dest, want *storagepb.Config
   137  		mask       *field_mask.FieldMask
   138  	}{
   139  		{
   140  			desc: "applyToBlank",
   141  			src:  apiTimeConfig,
   142  			dest: &storagepb.Config{},
   143  			mask: &field_mask.FieldMask{Paths: []string{statePath, maxTokensPath}},
   144  			want: &storagepb.Config{
   145  				State:     storagepb.Config_DISABLED,
   146  				MaxTokens: apiTimeConfig.MaxTokens,
   147  			},
   148  		},
   149  		{
   150  			desc: "sequencingBasedOverwrite",
   151  			src:  apiSequencingConfig,
   152  			dest: &destSequencingConfig,
   153  			mask: sequencingBasedMask,
   154  			want: storageSequencingConfig,
   155  		},
   156  		{
   157  			desc: "timeBasedOverwrite",
   158  			src:  apiTimeConfig,
   159  			dest: &destTimeConfig,
   160  			mask: timeBasedMask,
   161  			want: storageTimeConfig,
   162  		},
   163  		{
   164  			desc: "clearSequencingIfNil",
   165  			src:  &quotapb.Config{},
   166  			dest: &destClearSequencing,
   167  			mask: &field_mask.FieldMask{Paths: []string{sequencingBasedPath}},
   168  			want: &wantClearSequencing,
   169  		},
   170  		{
   171  			desc: "clearTimeIfNil",
   172  			src:  &quotapb.Config{},
   173  			dest: &destClearTime,
   174  			mask: &field_mask.FieldMask{Paths: []string{timeBasedPath}},
   175  			want: &wantClearTime,
   176  		},
   177  	}
   178  	for _, test := range tests {
   179  		applyMask(test.src, test.dest, test.mask)
   180  		if !proto.Equal(test.dest, test.want) {
   181  			t.Errorf("%v: post-applyMask() diff (-got +want):\n%v", test.desc, pretty.Compare(test.dest, test.want))
   182  		}
   183  	}
   184  }
   185  
   186  func TestConvert_APIAndStorage(t *testing.T) {
   187  	tests := []struct {
   188  		desc    string
   189  		api     *quotapb.Config
   190  		storage *storagepb.Config
   191  	}{
   192  		{
   193  			desc:    "sequencingBased",
   194  			api:     apiSequencingConfig,
   195  			storage: storageSequencingConfig,
   196  		},
   197  		{
   198  			desc:    "timeBased",
   199  			api:     apiTimeConfig,
   200  			storage: storageTimeConfig,
   201  		},
   202  		{
   203  			desc:    "zeroed",
   204  			api:     &quotapb.Config{},
   205  			storage: &storagepb.Config{},
   206  		},
   207  	}
   208  	for _, test := range tests {
   209  		if got, want := convertToAPI(test.storage), test.api; !proto.Equal(got, want) {
   210  			t.Errorf("%v: post-convertToAPI() diff (-got +want):\n%v", test.desc, pretty.Compare(got, want))
   211  		}
   212  		if got, want := convertToStorage(test.api), test.storage; !proto.Equal(got, want) {
   213  			t.Errorf("%v: post-convertToStorage() diff (-got +want):\n%v", test.desc, pretty.Compare(got, want))
   214  		}
   215  	}
   216  }