github.com/openfga/openfga@v1.5.4-rc1/internal/keys/hasher_test.go (about) 1 package keys 2 3 import ( 4 "testing" 5 6 "github.com/cespare/xxhash/v2" 7 openfgav1 "github.com/openfga/api/proto/openfga/v1" 8 "github.com/stretchr/testify/require" 9 10 "github.com/openfga/openfga/pkg/testutils" 11 "github.com/openfga/openfga/pkg/tuple" 12 ) 13 14 func TestTupleKeysHasherSortsFirst(t *testing.T) { 15 var testCases = map[string]struct { 16 tuplesReversed []*openfgav1.TupleKey 17 tuplesOriginal []*openfgav1.TupleKey 18 }{ 19 `unordered_users`: { 20 tuplesReversed: []*openfgav1.TupleKey{ 21 tuple.NewTupleKey("document:A", "relationA", "user:A"), 22 tuple.NewTupleKey("document:A", "relationA", "user:B"), 23 tuple.NewTupleKey("document:A", "relationA", "user:C"), 24 }, 25 tuplesOriginal: []*openfgav1.TupleKey{ 26 tuple.NewTupleKey("document:A", "relationA", "user:C"), 27 tuple.NewTupleKey("document:A", "relationA", "user:B"), 28 tuple.NewTupleKey("document:A", "relationA", "user:A"), 29 }, 30 }, 31 `unordered_relations`: { 32 tuplesReversed: []*openfgav1.TupleKey{ 33 tuple.NewTupleKey("document:A", "relationA", "user:A"), 34 tuple.NewTupleKey("document:A", "relationB", "user:A"), 35 tuple.NewTupleKey("document:A", "relationC", "user:A"), 36 }, 37 tuplesOriginal: []*openfgav1.TupleKey{ 38 tuple.NewTupleKey("document:A", "relationC", "user:A"), 39 tuple.NewTupleKey("document:A", "relationB", "user:A"), 40 tuple.NewTupleKey("document:A", "relationA", "user:A"), 41 }, 42 }, 43 `unordered_objects`: { 44 tuplesReversed: []*openfgav1.TupleKey{ 45 tuple.NewTupleKey("document:A", "relationA", "user:A"), 46 tuple.NewTupleKey("document:B", "relationA", "user:A"), 47 tuple.NewTupleKey("document:C", "relationA", "user:A"), 48 }, 49 tuplesOriginal: []*openfgav1.TupleKey{ 50 tuple.NewTupleKey("document:C", "relationA", "user:A"), 51 tuple.NewTupleKey("document:B", "relationA", "user:A"), 52 tuple.NewTupleKey("document:A", "relationA", "user:A"), 53 }, 54 }, 55 `unordered_relations_users_and_objects`: { 56 tuplesReversed: []*openfgav1.TupleKey{ 57 tuple.NewTupleKey("document:A", "relationA", "user:A"), 58 tuple.NewTupleKey("document:A", "relationA", "user:B"), 59 tuple.NewTupleKey("document:A", "relationB", "user:A"), 60 tuple.NewTupleKey("document:A", "relationB", "user:B"), 61 tuple.NewTupleKey("document:B", "relationA", "user:A"), 62 tuple.NewTupleKey("document:B", "relationA", "user:B"), 63 tuple.NewTupleKey("document:B", "relationB", "user:A"), 64 tuple.NewTupleKey("document:B", "relationB", "user:B"), 65 }, 66 tuplesOriginal: []*openfgav1.TupleKey{ 67 tuple.NewTupleKey("document:B", "relationB", "user:B"), 68 tuple.NewTupleKey("document:B", "relationB", "user:A"), 69 tuple.NewTupleKey("document:B", "relationA", "user:B"), 70 tuple.NewTupleKey("document:B", "relationA", "user:A"), 71 tuple.NewTupleKey("document:A", "relationB", "user:B"), 72 tuple.NewTupleKey("document:A", "relationB", "user:A"), 73 tuple.NewTupleKey("document:A", "relationA", "user:B"), 74 tuple.NewTupleKey("document:A", "relationA", "user:A"), 75 }, 76 }, 77 } 78 for name, test := range testCases { 79 t.Run(name, func(t *testing.T) { 80 hasher1 := NewCacheKeyHasher(xxhash.New()) 81 tuplesHasher := NewTupleKeysHasher(test.tuplesOriginal...) 82 require.NoError(t, tuplesHasher.Append(hasher1)) 83 84 hasher2 := NewCacheKeyHasher(xxhash.New()) 85 tuplesInvertedHasher := NewTupleKeysHasher(test.tuplesReversed...) 86 require.NoError(t, tuplesInvertedHasher.Append(hasher2)) 87 88 require.Equal(t, hasher1.Key().ToUInt64(), hasher2.Key().ToUInt64()) 89 }) 90 } 91 } 92 93 func TestContextHasher(t *testing.T) { 94 var testCases = []struct { 95 name string 96 context1 map[string]any 97 context2 map[string]any 98 equal bool 99 }{ 100 { 101 context1: map[string]any{ 102 "x": []any{"1", "2"}, 103 }, 104 context2: map[string]any{ 105 "x": []any{"2", "1"}, 106 }, 107 equal: false, 108 }, 109 { 110 context1: map[string]any{ 111 "x": []any{1}, 112 }, 113 context2: map[string]any{ 114 "x": []any{"1"}, 115 }, 116 equal: true, 117 }, 118 { 119 context1: map[string]any{ 120 "x": []any{1}, 121 }, 122 context2: map[string]any{ 123 "x": []any{"1.1"}, 124 }, 125 equal: false, 126 }, 127 { 128 context1: map[string]any{ 129 "x": []any{1.0}, 130 }, 131 context2: map[string]any{ 132 "x": []any{1}, 133 }, 134 equal: true, 135 }, 136 { 137 context1: map[string]any{ 138 "x": []any{float64(3) / 2}, 139 }, 140 context2: map[string]any{ 141 "x": []any{1}, 142 }, 143 equal: false, 144 }, 145 { 146 context1: map[string]any{ 147 "x": []any{3 / 2}, 148 }, 149 context2: map[string]any{ 150 "x": []any{1}, 151 }, 152 equal: true, 153 }, 154 { 155 context1: map[string]any{ 156 "x": []any{float64(1) / 1}, 157 }, 158 context2: map[string]any{ 159 "x": []any{1}, 160 }, 161 equal: true, 162 }, 163 { 164 context1: map[string]any{ 165 "x": []any{0.000011}, 166 }, 167 context2: map[string]any{ 168 "x": []any{0.0000112}, 169 }, 170 equal: false, 171 }, 172 } 173 174 for _, test := range testCases { 175 t.Run(test.name, func(t *testing.T) { 176 hasher1 := NewCacheKeyHasher(xxhash.New()) 177 178 struct1 := testutils.MustNewStruct(t, test.context1) 179 err := NewContextHasher(struct1).Append(hasher1) 180 require.NoError(t, err) 181 key1 := hasher1.Key().ToUInt64() 182 183 hasher2 := NewCacheKeyHasher(xxhash.New()) 184 struct2 := testutils.MustNewStruct(t, test.context2) 185 err = NewContextHasher(struct2).Append(hasher2) 186 require.NoError(t, err) 187 key2 := hasher2.Key().ToUInt64() 188 189 if test.equal { 190 require.Equal(t, key1, key2) 191 } else { 192 require.NotEqual(t, key1, key2) 193 } 194 }) 195 } 196 }