github.com/m3db/m3@v1.5.0/src/dbnode/client/iterator_matcher.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package client
    22  
    23  import (
    24  	"fmt"
    25  
    26  	"github.com/m3db/m3/src/x/ident"
    27  
    28  	"github.com/golang/mock/gomock"
    29  )
    30  
    31  // TaggedIDsIteratorMatcher is a gomock.Matcher that matches TaggedIDsIterator.
    32  type TaggedIDsIteratorMatcher interface {
    33  	gomock.Matcher
    34  }
    35  
    36  // TaggedIDsIteratorMatcherOption is an option for the TaggedIDsIteratorMatcher ctor.
    37  type TaggedIDsIteratorMatcherOption struct {
    38  	Namespace string
    39  	ID        string
    40  	Tags      []string
    41  }
    42  
    43  // MustNewTaggedIDsIteratorMatcher returns a new TaggedIDsIteratorMatcher.
    44  func MustNewTaggedIDsIteratorMatcher(opts ...TaggedIDsIteratorMatcherOption) TaggedIDsIteratorMatcher {
    45  	m, err := NewTaggedIDsIteratorMatcher(opts...)
    46  	if err != nil {
    47  		panic(err.Error())
    48  	}
    49  	return m
    50  }
    51  
    52  // NewTaggedIDsIteratorMatcher returns a new TaggedIDsIteratorMatcher.
    53  func NewTaggedIDsIteratorMatcher(opts ...TaggedIDsIteratorMatcherOption) (TaggedIDsIteratorMatcher, error) {
    54  	m := &iteratorMatcher{}
    55  	err := m.init(opts)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	return m, nil
    60  }
    61  
    62  // ns -> id -> tags
    63  type nsIDTagsMap map[string]idTagsMap
    64  type idTagsMap map[string]ident.TagIterMatcher
    65  
    66  type iteratorMatcher struct {
    67  	entries nsIDTagsMap
    68  }
    69  
    70  func (m *iteratorMatcher) init(opts []TaggedIDsIteratorMatcherOption) error {
    71  	m.entries = make(nsIDTagsMap)
    72  	for _, o := range opts {
    73  		idMap, ok := m.entries[o.Namespace]
    74  		if !ok {
    75  			idMap = make(idTagsMap)
    76  			m.entries[o.Namespace] = idMap
    77  		}
    78  		_, ok = idMap[o.ID]
    79  		if ok {
    80  			return fmt.Errorf("duplicate id: %s", o.ID)
    81  		}
    82  		iter, err := ident.NewTagStringsIterator(o.Tags...)
    83  		if err != nil {
    84  			return err
    85  		}
    86  		matcher := ident.NewTagIterMatcher(iter)
    87  		idMap[o.ID] = matcher
    88  	}
    89  	return nil
    90  }
    91  
    92  func (m *iteratorMatcher) Matches(x interface{}) bool {
    93  	iter, ok := x.(TaggedIDsIterator)
    94  	if !ok {
    95  		return false
    96  	}
    97  	for iter.Next() {
    98  		ns, id, tags := iter.Current()
    99  		idMap, ok := m.entries[ns.String()]
   100  		if !ok {
   101  			return false
   102  		}
   103  		matcher, ok := idMap[id.String()]
   104  		if !ok {
   105  			return false
   106  		}
   107  		if !matcher.Matches(tags.Duplicate()) {
   108  			return false
   109  		}
   110  		delete(idMap, id.String())
   111  	}
   112  	if iter.Next() || iter.Err() != nil {
   113  		return false
   114  	}
   115  	for _, ids := range m.entries {
   116  		if len(ids) != 0 {
   117  			return false
   118  		}
   119  	}
   120  	return true
   121  }
   122  
   123  func (m *iteratorMatcher) String() string {
   124  	return fmt.Sprintf("TaggedIDsIteratorMatcher %v", m.entries)
   125  }