1
+ package com .redis .om .spring .issues ;
2
+
3
+ import static org .assertj .core .api .Assertions .assertThat ;
4
+ import static org .junit .jupiter .api .Assertions .*;
5
+
6
+ import java .util .List ;
7
+ import java .util .Optional ;
8
+
9
+ import org .junit .jupiter .api .AfterEach ;
10
+ import org .junit .jupiter .api .BeforeEach ;
11
+ import org .junit .jupiter .api .Test ;
12
+ import org .springframework .beans .factory .annotation .Autowired ;
13
+ import org .springframework .boot .autoconfigure .SpringBootApplication ;
14
+ import org .springframework .boot .test .context .SpringBootTest ;
15
+ import org .springframework .context .annotation .Bean ;
16
+ import org .springframework .context .annotation .Configuration ;
17
+ import org .springframework .context .annotation .Primary ;
18
+ import org .springframework .data .geo .Point ;
19
+ import org .springframework .data .redis .core .RedisTemplate ;
20
+ import org .springframework .data .redis .core .mapping .RedisMappingContext ;
21
+ import org .springframework .test .annotation .DirtiesContext ;
22
+ import org .testcontainers .junit .jupiter .Testcontainers ;
23
+
24
+ import com .google .gson .JsonObject ;
25
+ import com .redis .om .spring .AbstractBaseOMTest ;
26
+ import com .redis .om .spring .TestConfig ;
27
+ import com .redis .om .spring .annotations .EnableRedisDocumentRepositories ;
28
+ import com .redis .om .spring .fixtures .document .model .MyDoc ;
29
+ import com .redis .om .spring .fixtures .document .repository .MyDocRepository ;
30
+ import com .redis .om .spring .mapping .RedisEnhancedMappingContext ;
31
+ import com .redis .om .spring .ops .RedisModulesOperations ;
32
+ import com .redis .om .spring .ops .json .JSONOperations ;
33
+ import com .redis .om .spring .ops .search .SearchOperations ;
34
+
35
+ /**
36
+ * Test for issue #637: "Not able to override keyValueMappingContext"
37
+ *
38
+ * This test verifies that users can now provide their own RedisEnhancedMappingContext
39
+ * bean with a custom keyspace resolver, without needing to set
40
+ * spring.main.allow-bean-definition-overriding=true
41
+ *
42
+ * The fix removes @Primary and adds @ConditionalOnMissingBean to allow user overrides.
43
+ */
44
+ @ Testcontainers
45
+ @ DirtiesContext
46
+ @ SpringBootTest (classes = Issue637CustomMappingContextTest .Config .class )
47
+ class Issue637CustomMappingContextTest extends AbstractBaseOMTest {
48
+
49
+ private static final String TENANT_PREFIX = "tenant_prod" ;
50
+
51
+ @ Autowired
52
+ MyDocRepository myDocRepository ;
53
+
54
+ @ Autowired
55
+ RedisTemplate <String , String > template ;
56
+
57
+ @ Autowired
58
+ RedisModulesOperations <String > modulesOperations ;
59
+
60
+ @ Autowired
61
+ RedisMappingContext mappingContext ;
62
+
63
+ String myDocId ;
64
+
65
+ @ BeforeEach
66
+ void loadTestData () {
67
+ Point point = new Point (-122.124500 , 47.640160 );
68
+ MyDoc myDoc = MyDoc .of ("issue 637 test" , point , point , 1 );
69
+ myDoc = myDocRepository .save (myDoc );
70
+ myDocId = myDoc .getId ();
71
+ }
72
+
73
+ @ AfterEach
74
+ void cleanUp () {
75
+ myDocRepository .deleteAll ();
76
+ }
77
+
78
+ @ Test
79
+ void testIssue637_CustomMappingContextIsUsed () {
80
+ // Verify our custom mapping context is being used
81
+ assertThat (mappingContext ).isInstanceOf (RedisEnhancedMappingContext .class );
82
+
83
+ // Verify the custom keyspace resolver is applied
84
+ String keyspace = mappingContext .getKeySpaceResolver ().resolveKeySpace (MyDoc .class );
85
+ assertThat (keyspace ).isEqualTo (TENANT_PREFIX + ":MyDoc" );
86
+ }
87
+
88
+ @ Test
89
+ void testIssue637_DocumentsUseCustomKeyspace () {
90
+ // Verify the document was saved with custom keyspace
91
+ JSONOperations <String > ops = modulesOperations .opsForJSON ();
92
+
93
+ // The key should use our custom prefix
94
+ String expectedKey = TENANT_PREFIX + ":MyDoc:" + myDocId ;
95
+ JsonObject rawJSON = ops .get (expectedKey , JsonObject .class );
96
+
97
+ assertNotNull (rawJSON , "Document should exist at custom keyspace" );
98
+ assertEquals (myDocId , rawJSON .get ("id" ).getAsString ());
99
+ }
100
+
101
+ @ Test
102
+ void testIssue637_SearchIndexUsesCustomKeyspace () {
103
+ SearchOperations <String > searchOps = modulesOperations .opsForSearch (MyDoc .class .getName () + "Idx" );
104
+ var info = searchOps .getInfo ();
105
+
106
+ @ SuppressWarnings ("unchecked" )
107
+ var definition = (List <Object >) info .get ("index_definition" );
108
+ assertNotNull (definition );
109
+
110
+ int prefixesIndex = definition .indexOf ("prefixes" );
111
+ assertTrue (prefixesIndex >= 0 , "Index definition should contain prefixes" );
112
+
113
+ @ SuppressWarnings ("unchecked" )
114
+ var prefixes = (List <String >) definition .get (prefixesIndex + 1 );
115
+ assertNotNull (prefixes );
116
+ assertEquals (1 , prefixes .size ());
117
+ assertEquals (TENANT_PREFIX + ":MyDoc:" , prefixes .get (0 ),
118
+ "Index should use custom keyspace prefix" );
119
+ }
120
+
121
+ @ Test
122
+ void testIssue637_RepositoryOperationsWork () {
123
+ // Test find by ID
124
+ Optional <MyDoc > maybeDoc = myDocRepository .findById (myDocId );
125
+ assertTrue (maybeDoc .isPresent ());
126
+ assertEquals ("issue 637 test" , maybeDoc .get ().getTitle ());
127
+
128
+ // Test update
129
+ MyDoc doc = maybeDoc .get ();
130
+ doc .setTitle ("updated title" );
131
+ myDocRepository .save (doc );
132
+
133
+ maybeDoc = myDocRepository .findById (myDocId );
134
+ assertTrue (maybeDoc .isPresent ());
135
+ assertEquals ("updated title" , maybeDoc .get ().getTitle ());
136
+
137
+ // Test delete
138
+ myDocRepository .deleteById (myDocId );
139
+ maybeDoc = myDocRepository .findById (myDocId );
140
+ assertFalse (maybeDoc .isPresent ());
141
+ }
142
+
143
+ @ SpringBootApplication
144
+ @ Configuration
145
+ @ EnableRedisDocumentRepositories (
146
+ basePackages = {
147
+ "com.redis.om.spring.fixtures.document.model" ,
148
+ "com.redis.om.spring.fixtures.document.repository"
149
+ }
150
+ )
151
+ static class Config extends TestConfig {
152
+
153
+ /**
154
+ * This demonstrates the fix for issue #637.
155
+ * Users can now provide their own RedisEnhancedMappingContext bean
156
+ * with a custom keyspace resolver.
157
+ *
158
+ * The @ConditionalOnMissingBean annotation on the default bean
159
+ * ensures this user-provided bean takes precedence without
160
+ * requiring spring.main.allow-bean-definition-overriding=true
161
+ */
162
+ @ Bean (name = "redisEnhancedMappingContext" )
163
+ @ Primary
164
+ public RedisEnhancedMappingContext customMappingContext () {
165
+ RedisEnhancedMappingContext mappingContext = new RedisEnhancedMappingContext ();
166
+
167
+ // Custom keyspace resolver for multi-tenant support
168
+ mappingContext .setKeySpaceResolver (type ->
169
+ TENANT_PREFIX + ":" + type .getSimpleName ());
170
+
171
+ return mappingContext ;
172
+ }
173
+ }
174
+ }
0 commit comments