18
18
import java .net .UnknownHostException ;
19
19
import java .util .Arrays ;
20
20
import java .util .Collection ;
21
+ import java .util .Collections ;
21
22
import java .util .HashSet ;
22
23
import java .util .Set ;
23
24
27
28
import org .slf4j .Logger ;
28
29
import org .slf4j .LoggerFactory ;
29
30
import org .springframework .util .CollectionUtils ;
31
+ import org .springframework .util .StringUtils ;
30
32
31
33
import com .mongodb .DB ;
34
+ import com .mongodb .DBCollection ;
32
35
import com .mongodb .MongoClient ;
33
36
34
37
/**
38
+ * {@link CleanMongoDB} is a junit {@link TestRule} implementation to be used as for wiping data from MongoDB instance.
39
+ * MongoDB specific system databases like {@literal admin} and {@literal local} remain untouched. The rule will apply
40
+ * <strong>after</strong> the base {@link Statement}. <br />
41
+ * Use as {@link org.junit.ClassRule} to wipe data after finishing all tests within a class or as {@link org.junit.Rule}
42
+ * to do so after each {@link org.junit.Test}.
43
+ *
35
44
* @author Christoph Strobl
45
+ * @since 1.6
36
46
*/
37
47
public class CleanMongoDB implements TestRule {
38
48
39
49
private static final Logger LOGGER = LoggerFactory .getLogger (CleanMongoDB .class );
40
50
41
- public enum Types {
51
+ /**
52
+ * Defines contents of MongoDB.
53
+ */
54
+ public enum Struct {
42
55
DATABASE , COLLECTION , INDEX ;
43
56
}
44
57
58
+ @ SuppressWarnings ("serial" )//
45
59
private Set <String > preserveDatabases = new HashSet <String >() {
46
-
47
- private static final long serialVersionUID = -8698807376808700046L ;
48
-
49
60
{
50
61
add ("admin" );
51
62
add ("local" );
@@ -54,57 +65,278 @@ public enum Types {
54
65
55
66
private Set <String > dbNames = new HashSet <String >();
56
67
private Set <String > collectionNames = new HashSet <String >();
57
- private Set <Types > types = new HashSet <CleanMongoDB .Types >();
68
+ private Set <Struct > types = new HashSet <CleanMongoDB .Struct >();
58
69
private MongoClient client ;
59
70
71
+ /**
72
+ * Create new instance using an internal {@link MongoClient}.
73
+ */
60
74
public CleanMongoDB () {
61
75
this (null );
62
76
}
63
77
78
+ /**
79
+ * Create new instance using an internal {@link MongoClient} connecting to specified instance running at host:port.
80
+ *
81
+ * @param host
82
+ * @param port
83
+ * @throws UnknownHostException
84
+ */
64
85
public CleanMongoDB (String host , int port ) throws UnknownHostException {
65
86
this (new MongoClient (host , port ));
66
87
}
67
88
89
+ /**
90
+ * Create new instance using the given client.
91
+ *
92
+ * @param client
93
+ */
68
94
public CleanMongoDB (MongoClient client ) {
69
95
this .client = client ;
70
96
}
71
97
98
+ /**
99
+ * Removes everything by dropping every single {@link DB}.
100
+ *
101
+ * @return
102
+ */
72
103
public static CleanMongoDB everything () {
73
104
74
105
CleanMongoDB cleanMongoDB = new CleanMongoDB ();
75
- cleanMongoDB .clean (Types .DATABASE );
106
+ cleanMongoDB .clean (Struct .DATABASE );
76
107
return cleanMongoDB ;
77
108
}
78
109
110
+ /**
111
+ * Removes everything from the databases with given name by dropping the according {@link DB}.
112
+ *
113
+ * @param dbNames
114
+ * @return
115
+ */
79
116
public static CleanMongoDB databases (String ... dbNames ) {
80
117
81
118
CleanMongoDB cleanMongoDB = new CleanMongoDB ();
82
- cleanMongoDB .clean (Types .DATABASE );
83
- cleanMongoDB .collectionNames .addAll (Arrays .asList (dbNames ));
119
+ cleanMongoDB .clean (Struct .DATABASE );
120
+ cleanMongoDB .useDatabases (dbNames );
121
+ return cleanMongoDB ;
122
+ }
123
+
124
+ /**
125
+ * Drops the {@link DBCollection} with given names from every single {@link DB} containing them.
126
+ *
127
+ * @param collectionNames
128
+ * @return
129
+ */
130
+ public static CleanMongoDB collections (String ... collectionNames ) {
131
+ return collections ("" , Arrays .asList (collectionNames ));
132
+ }
133
+
134
+ /**
135
+ * Drops the {@link DBCollection} with given names from the named {@link DB}.
136
+ *
137
+ * @param dbName
138
+ * @param collectionNames
139
+ * @return
140
+ */
141
+ public static CleanMongoDB collections (String dbName , Collection <String > collectionNames ) {
142
+
143
+ CleanMongoDB cleanMongoDB = new CleanMongoDB ();
144
+ cleanMongoDB .clean (Struct .COLLECTION );
145
+ cleanMongoDB .useCollections (dbName , collectionNames );
84
146
return cleanMongoDB ;
85
147
}
86
148
149
+ /**
150
+ * Drops all index structures from every single {@link DBCollection}.
151
+ *
152
+ * @return
153
+ */
87
154
public static CleanMongoDB indexes () {
155
+ return indexes (Collections .<String > emptySet ());
156
+ }
157
+
158
+ /**
159
+ * Drops all index structures from every single {@link DBCollection}.
160
+ *
161
+ * @param collectionNames
162
+ * @return
163
+ */
164
+ public static CleanMongoDB indexes (Collection <String > collectionNames ) {
88
165
89
166
CleanMongoDB cleanMongoDB = new CleanMongoDB ();
90
- cleanMongoDB .clean (Types .INDEX );
167
+ cleanMongoDB .clean (Struct .INDEX );
168
+ cleanMongoDB .useCollections (collectionNames );
91
169
return cleanMongoDB ;
92
170
}
93
171
94
- public CleanMongoDB clean (Types ... types ) {
172
+ /**
173
+ * Define {@link Struct} to be cleaned.
174
+ *
175
+ * @param types
176
+ * @return
177
+ */
178
+ public CleanMongoDB clean (Struct ... types ) {
95
179
96
180
this .types .addAll (Arrays .asList (types ));
97
181
return this ;
98
182
}
99
183
100
- public Statement apply () {
184
+ /**
185
+ * Defines the {@link DB}s to be used. <br />
186
+ * Impact along with {@link CleanMongoDB#clean(Struct...)}:
187
+ * <ul>
188
+ * <li>{@link Struct#DATABASE}: Forces drop of named databases.</li>
189
+ * <li>{@link Struct#COLLECTION}: Forces drop of collections within named databases.</li>
190
+ * <li>{@link Struct#INDEX}: Removes index within collections of named databases.</li>
191
+ * </ul>
192
+ *
193
+ * @param dbNames
194
+ * @return
195
+ */
196
+ public CleanMongoDB useDatabases (String ... dbNames ) {
197
+
198
+ this .dbNames .addAll (Arrays .asList (dbNames ));
199
+ return this ;
200
+ }
201
+
202
+ /**
203
+ * Excludes the given {@link DB}s from being processed.
204
+ *
205
+ * @param dbNames
206
+ * @return
207
+ */
208
+ public CleanMongoDB preserveDatabases (String ... dbNames ) {
209
+ this .preserveDatabases .addAll (Arrays .asList (dbNames ));
210
+ return this ;
211
+ }
212
+
213
+ /**
214
+ * Defines the {@link DBCollection}s to be used. <br />
215
+ * Impact along with {@link CleanMongoDB#clean(Struct...)}:
216
+ * <ul>
217
+ * <li>{@link Struct#COLLECTION}: Forces drop of named collections.</li>
218
+ * <li>{@link Struct#INDEX}: Removes index within named collections.</li>
219
+ * </ul>
220
+ *
221
+ * @param collectionNames
222
+ * @return
223
+ */
224
+ public CleanMongoDB useCollections (String ... collectionNames ) {
225
+ return useCollections (Arrays .asList (collectionNames ));
226
+ }
227
+
228
+ private CleanMongoDB useCollections (Collection <String > collectionNames ) {
229
+ return useCollections ("" , collectionNames );
230
+ }
231
+
232
+ /**
233
+ * Defines the {@link DBCollection}s and {@link DB} to be used. <br />
234
+ * Impact along with {@link CleanMongoDB#clean(Struct...)}:
235
+ * <ul>
236
+ * <li>{@link Struct#COLLECTION}: Forces drop of named collections in given db.</li>
237
+ * <li>{@link Struct#INDEX}: Removes index within named collections in given db.</li>
238
+ * </ul>
239
+ *
240
+ * @param collectionNames
241
+ * @return
242
+ */
243
+ public CleanMongoDB useCollections (String db , Collection <String > collectionNames ) {
244
+
245
+ if (StringUtils .hasText (db )) {
246
+ this .dbNames .add (db );
247
+ }
248
+
249
+ if (!CollectionUtils .isEmpty (collectionNames )) {
250
+ this .collectionNames .addAll (collectionNames );
251
+ }
252
+ return this ;
253
+ }
254
+
255
+ Statement apply () {
101
256
return apply (null , null );
102
257
}
103
258
259
+ /*
260
+ * (non-Javadoc)
261
+ * @see org.junit.rules.TestRule#apply(org.junit.runners.model.Statement, org.junit.runner.Description)
262
+ */
104
263
public Statement apply (Statement base , Description description ) {
105
264
return new MongoCleanStatement (base );
106
265
}
107
266
267
+ private void doClean () {
268
+
269
+ Collection <String > dbNamesToUse = initDbNames ();
270
+
271
+ for (String dbName : dbNamesToUse ) {
272
+
273
+ if (isPreserved (dbName ) || dropDbIfRequired (dbName )) {
274
+ continue ;
275
+ }
276
+
277
+ DB db = client .getDB (dbName );
278
+ dropCollectionsOrIndexIfRequried (db , initCollectionNames (db ));
279
+ }
280
+ }
281
+
282
+ private boolean dropDbIfRequired (String dbName ) {
283
+
284
+ if (!types .contains (Struct .DATABASE )) {
285
+ return false ;
286
+ }
287
+
288
+ client .dropDatabase (dbName );
289
+ LOGGER .debug ("Dropping DB '{}'. " , dbName );
290
+ return true ;
291
+ }
292
+
293
+ private void dropCollectionsOrIndexIfRequried (DB db , Collection <String > collectionsToUse ) {
294
+
295
+ for (String collectionName : collectionsToUse ) {
296
+
297
+ if (db .collectionExists (collectionName )) {
298
+
299
+ DBCollection collection = db .getCollectionFromString (collectionName );
300
+ if (collection != null ) {
301
+
302
+ if (types .contains (Struct .COLLECTION )) {
303
+ collection .drop ();
304
+ LOGGER .debug ("Dropping collection '{}' for DB '{}'. " , collectionName , db .getName ());
305
+ } else if (types .contains (Struct .INDEX )) {
306
+ collection .dropIndexes ();
307
+ LOGGER .debug ("Dropping indexes in collection '{}' for DB '{}'. " , collectionName , db .getName ());
308
+ }
309
+ }
310
+ }
311
+ }
312
+ }
313
+
314
+ private boolean isPreserved (String dbName ) {
315
+ return preserveDatabases .contains (dbName .toLowerCase ());
316
+ }
317
+
318
+ private Collection <String > initDbNames () {
319
+
320
+ Collection <String > dbNamesToUse = dbNames ;
321
+ if (dbNamesToUse .isEmpty ()) {
322
+ dbNamesToUse = client .getDatabaseNames ();
323
+ }
324
+ return dbNamesToUse ;
325
+ }
326
+
327
+ private Collection <String > initCollectionNames (DB db ) {
328
+
329
+ Collection <String > collectionsToUse = collectionNames ;
330
+ if (CollectionUtils .isEmpty (collectionsToUse )) {
331
+ collectionsToUse = db .getCollectionNames ();
332
+ }
333
+ return collectionsToUse ;
334
+ }
335
+
336
+ /**
337
+ * @author Christoph Strobl
338
+ * @since 1.6
339
+ */
108
340
private class MongoCleanStatement extends Statement {
109
341
110
342
private final Statement base ;
@@ -126,61 +358,12 @@ public void evaluate() throws Throwable {
126
358
isInternal = true ;
127
359
}
128
360
129
- Collection <String > dbNamesToUse = dbNames ;
130
- if (dbNamesToUse .isEmpty ()) {
131
- dbNamesToUse = client .getDatabaseNames ();
132
- }
133
-
134
- for (String dbName : dbNamesToUse ) {
135
-
136
- if (preserveDatabases .contains (dbName .toLowerCase ())) {
137
- continue ;
138
- }
139
-
140
- if (types .contains (Types .DATABASE )) {
141
- client .dropDatabase (dbName );
142
- LOGGER .debug ("Dropping DB '{}'. " , dbName );
143
- }
144
-
145
- if (types .contains (Types .COLLECTION )) {
146
-
147
- DB db = client .getDB (dbName );
148
- Collection <String > collectionsToUse = initCollectionNames (db );
149
- for (String collectionName : collectionsToUse ) {
150
- if (db .collectionExists (collectionName )) {
151
- db .getCollectionFromString (collectionName ).drop ();
152
- LOGGER .debug ("Dropping collection '{}' for DB '{}'. " , collectionName , dbName );
153
- }
154
- }
155
- }
156
-
157
- if (types .contains (Types .INDEX )) {
158
-
159
- DB db = client .getDB (dbName );
160
- Collection <String > collectionsToUse = initCollectionNames (db );
161
- for (String collectionName : collectionsToUse ) {
162
- if (db .collectionExists (collectionName )) {
163
- db .getCollectionFromString (collectionName ).dropIndexes ();
164
- LOGGER .debug ("Dropping indexes in collection '{}' for DB '{}'. " , collectionName , dbName );
165
- }
166
- }
167
- }
168
- }
361
+ doClean ();
169
362
170
363
if (isInternal ) {
171
364
client .close ();
172
365
client = null ;
173
366
}
174
367
}
175
-
176
- private Collection <String > initCollectionNames (DB db ) {
177
-
178
- Collection <String > collectionsToUse = collectionNames ;
179
- if (CollectionUtils .isEmpty (collectionsToUse )) {
180
- collectionsToUse = db .getCollectionNames ();
181
- }
182
- return collectionsToUse ;
183
- }
184
368
}
185
-
186
369
}
0 commit comments