44import static com .google .cloud .solutions .spannerddl .diff .DdlDiff .ALLOW_RECREATE_CONSTRAINTS_OPT ;
55import static com .google .cloud .solutions .spannerddl .diff .DdlDiff .ALLOW_RECREATE_INDEXES_OPT ;
66import static com .google .common .truth .Truth .assertWithMessage ;
7- import static org .junit .Assert .fail ;
87
98import com .google .cloud .solutions .spannerddl .testUtils .ReadTestDatafile ;
9+ import com .google .common .base .Joiner ;
1010import com .google .common .base .Splitter ;
1111import com .google .common .collect .ImmutableMap ;
1212import com .google .common .collect .Iterables ;
13+ import com .google .common .collect .MapDifference ;
14+ import com .google .common .collect .Maps ;
1315import java .io .IOException ;
16+ import java .util .ArrayList ;
1417import java .util .Arrays ;
15- import java .util .Collections ;
16- import java .util .Iterator ;
18+ import java .util .Collection ;
1719import java .util .List ;
1820import java .util .Map ;
1921import java .util .regex .Pattern ;
2022import java .util .stream .Collectors ;
2123import org .junit .Test ;
22- import org .slf4j .Logger ;
23- import org .slf4j .LoggerFactory ;
24+ import org .junit .runner .RunWith ;
25+ import org .junit .runners .Parameterized ;
26+ import org .junit .runners .Parameterized .Parameter ;
27+ import org .junit .runners .Parameterized .Parameters ;
2428
29+ @ RunWith (Parameterized .class )
2530public class DdlDiffFromFilesTest {
26- private static final Logger LOG = LoggerFactory .getLogger (DdlDiffFromFilesTest .class );
2731
28- @ Test
29- public void compareDddTextFiles () throws IOException {
32+ @ Parameter (0 )
33+ public String segmentName ;
34+
35+ @ Parameter (1 )
36+ public String originalSegment ;
37+
38+ @ Parameter (2 )
39+ public String newSegment ;
40+
41+ @ Parameter (3 )
42+ public String expectedOutput ;
43+
44+ @ Parameters (name = "{index}: {0}" )
45+ public static Collection <Object []> data () throws IOException {
3046 // Uses 3 files: 2 containing DDL segments to run diffs on, 1 with the expected results
3147 // if allowRecreateIndexes and allowDropStatements are set.
3248
@@ -36,114 +52,111 @@ public void compareDddTextFiles() throws IOException {
3652 Map <String , String > expectedOutputs =
3753 ReadTestDatafile .readDdlSegmentsFromFile ("expectedDdlDiff.txt" );
3854
39- Iterator <Map .Entry <String , String >> originalSegmentIt = originalSegments .entrySet ().iterator ();
40- Iterator <Map .Entry <String , String >> newSegmentIt = newSegments .entrySet ().iterator ();
41- Iterator <Map .Entry <String , String >> expectedOutputIt = expectedOutputs .entrySet ().iterator ();
42-
43- String segmentName = null ;
44- try {
45- while (originalSegmentIt .hasNext () && newSegmentIt .hasNext () && expectedOutputIt .hasNext ()) {
46- Map .Entry <String , String > originalSegment = originalSegmentIt .next ();
47- segmentName = originalSegment .getKey ();
48- Map .Entry <String , String > newSegment = newSegmentIt .next ();
49- Map .Entry <String , String > expectedOutput = expectedOutputIt .next ();
50-
51- // verify segment name order for sanity.
52- assertWithMessage ("section name in newDdl.txt differs from originalDdl.txt" )
53- .that (segmentName )
54- .isEqualTo (newSegment .getKey ());
55- assertWithMessage ("section name in expectedDdlDiff.txt differs from originalDdl.txt" )
56- .that (segmentName )
57- .isEqualTo (expectedOutput .getKey ());
58-
59- List <String > expectedDiff =
60- expectedOutput .getValue () != null
61- ? Arrays .asList (expectedOutput .getValue ().split ("\n " ))
62- : Collections .emptyList ();
63-
64- LOG .info ("Processing segment (with drops): " + segmentName );
65- DdlDiff ddlDiff =
66- DdlDiff .build (
67- originalSegment .getValue (),
68- newSegment .getValue (),
69- ImmutableMap .of (DdlDiff .IGNORE_PROTO_BUNDLES_OPT , false ));
70- // Run diff with allowRecreateIndexes and allowDropStatements
71- List <String > diff =
72- ddlDiff .generateDifferenceStatements (
73- ImmutableMap .of (
74- ALLOW_RECREATE_INDEXES_OPT ,
75- true ,
76- ALLOW_DROP_STATEMENTS_OPT ,
77- true ,
78- ALLOW_RECREATE_CONSTRAINTS_OPT ,
79- true ));
80- // check expected results.
81- assertWithMessage ("Mismatch for section %s" , segmentName )
82- .that (diff )
83- .isEqualTo (expectedDiff );
84-
85- // TEST PART 2: with allowDropStatements=false
86-
87- // build an expectedResults without any drops.
88- List <String > expectedDiffNoDrops =
89- expectedDiff .stream ()
90- .filter (
91- statement ->
92- !statement .matches (
93- ".*DROP (SCHEMA|TABLE|COLUMN|CHANGE STREAM|SEARCH INDEX).*" ))
94- .collect (Collectors .toList ());
95-
96- // remove any drop indexes from the expectedResults if they do not have an equivalent
97- // CREATE statement. This is because we are allowing recreation of indexes, but not allowing
98- // dropping of removed indexes.
99- for (String statement : expectedDiff ) {
100- if (statement .startsWith ("DROP INDEX " )) {
101- String indexName = Iterables .get (Splitter .on (' ' ).split (statement ), 2 );
102- // see if there is a matching create statement
103- Pattern p = Pattern .compile ("CREATE .*INDEX " + indexName + " " );
104- if (expectedDiffNoDrops .stream ().noneMatch (s -> p .matcher (s ).find ())) {
105- expectedDiffNoDrops .remove (statement );
106- }
107- }
108- }
109-
110- LOG .info ("Processing segment (without drops): " + segmentName );
111- diff =
112- ddlDiff .generateDifferenceStatements (
113- ImmutableMap .of (
114- ALLOW_RECREATE_INDEXES_OPT ,
115- true ,
116- ALLOW_DROP_STATEMENTS_OPT ,
117- false ,
118- ALLOW_RECREATE_CONSTRAINTS_OPT ,
119- true ));
120- // check expected results.
121- assertWithMessage ("Mismatch for section (noDrops)%s" , segmentName )
122- .that (diff )
123- .isEqualTo (expectedDiffNoDrops );
124- }
125- } catch (DdlDiffException e ) {
126- fail ("DdlDiffException when processing segment:\n '" + segmentName + "''\n " + e .getMessage ());
127- } catch (Exception e ) {
128- throw new Error (
129- "Unexpected exception when processing segment \n '" + segmentName + "'\n " + e .getMessage (),
130- e );
55+ // Validate that all the segments are in all files
56+ ArrayList <String > errors = new ArrayList <>();
57+ MapDifference <String , String > diff = Maps .difference (originalSegments , newSegments );
58+ if (!diff .entriesOnlyOnLeft ().isEmpty ()) {
59+ errors .add (
60+ "Mismatch in segments: newDdl.txt is missing segments: "
61+ + diff .entriesOnlyOnLeft ().keySet ());
13162 }
132-
133- if (originalSegmentIt .hasNext ()) {
134- throw new Error (
135- "Mismatched number of segments: Others have finished, but Original still has "
136- + originalSegmentIt .next ().getKey ());
63+ if (!diff .entriesOnlyOnRight ().isEmpty ()) {
64+ errors .add (
65+ "Mismatch in segments: newDdl.txt has additional segments: "
66+ + diff .entriesOnlyOnRight ().keySet ());
13767 }
138- if (newSegmentIt .hasNext ()) {
139- throw new Error (
140- "Mismatched number of segments: Others have finished, but New still has "
141- + newSegmentIt .next ().getKey ());
68+ diff = Maps .difference (originalSegments , expectedOutputs );
69+ if (!diff .entriesOnlyOnLeft ().isEmpty ()) {
70+ errors .add (
71+ "Mismatch in segments: expectedDdlDiff.txt is missing segments: "
72+ + diff .entriesOnlyOnLeft ().keySet ());
73+ }
74+ if (!diff .entriesOnlyOnRight ().isEmpty ()) {
75+ errors .add (
76+ "Mismatch in segments: expectedDdlDiff.txt has additional segments: "
77+ + diff .entriesOnlyOnRight ().keySet ());
78+ }
79+
80+ if (!errors .isEmpty ()) {
81+ assertWithMessage (
82+ "Mismatching segments in test data:\n %s" , Joiner .on ("\n " ).join (errors ))
83+ .fail ();
14284 }
143- if (expectedOutputIt .hasNext ()) {
144- throw new Error (
145- "Mismatched number of segments: Others have finished, but Expected still has "
146- + expectedOutputIt .next ().getKey ());
85+ return originalSegments .entrySet ().stream ()
86+ .map (
87+ (e ) ->
88+ new Object [] {
89+ e .getKey (),
90+ e .getValue (),
91+ newSegments .get (e .getKey ()),
92+ expectedOutputs .get (e .getKey ())
93+ })
94+ .collect (Collectors .toList ());
95+ }
96+
97+ @ Test
98+ public void compareDddWithDrops () throws DdlDiffException {
99+
100+ List <String > expectedDiff =
101+ expectedOutput == null ? List .of () : Arrays .asList (expectedOutput .split ("\n " ));
102+
103+ DdlDiff ddlDiff =
104+ DdlDiff .build (
105+ originalSegment , newSegment , ImmutableMap .of (DdlDiff .IGNORE_PROTO_BUNDLES_OPT , false ));
106+ // Run diff with allowRecreateIndexes and allowDropStatements
107+ List <String > diff =
108+ ddlDiff .generateDifferenceStatements (
109+ ImmutableMap .of (
110+ ALLOW_RECREATE_INDEXES_OPT ,
111+ true ,
112+ ALLOW_DROP_STATEMENTS_OPT ,
113+ true ,
114+ ALLOW_RECREATE_CONSTRAINTS_OPT ,
115+ true ));
116+ // check expected results.
117+ assertWithMessage ("Mismatch for section %s" , segmentName ).that (diff ).isEqualTo (expectedDiff );
118+ }
119+
120+ @ Test
121+ public void compareDddNoDrops () throws DdlDiffException {
122+ // build an expectedResults without any drops.
123+ List <String > expectedDiff =
124+ expectedOutput == null ? List .of () : Arrays .asList (expectedOutput .split ("\n " ));
125+ List <String > expectedDiffNoDrops =
126+ expectedDiff .stream ()
127+ .filter (
128+ statement ->
129+ !statement .matches (".*DROP (SCHEMA|TABLE|COLUMN|CHANGE STREAM|SEARCH INDEX).*" ))
130+ .collect (Collectors .toList ());
131+
132+ // remove any drop indexes from the expectedResults if they do not have an equivalent
133+ // CREATE statement. This is because we are allowing recreation of indexes, but not allowing
134+ // dropping of removed indexes.
135+ for (String statement : expectedDiff ) {
136+ if (statement .startsWith ("DROP INDEX " )) {
137+ String indexName = Iterables .get (Splitter .on (' ' ).split (statement ), 2 );
138+ // see if there is a matching create statement
139+ Pattern p = Pattern .compile ("CREATE .*INDEX " + indexName + " " );
140+ if (expectedDiffNoDrops .stream ().noneMatch (s -> p .matcher (s ).find ())) {
141+ expectedDiffNoDrops .remove (statement );
142+ }
143+ }
147144 }
145+ DdlDiff ddlDiff =
146+ DdlDiff .build (
147+ originalSegment , newSegment , ImmutableMap .of (DdlDiff .IGNORE_PROTO_BUNDLES_OPT , false ));
148+ List <String > diff =
149+ ddlDiff .generateDifferenceStatements (
150+ ImmutableMap .of (
151+ ALLOW_RECREATE_INDEXES_OPT ,
152+ true ,
153+ ALLOW_DROP_STATEMENTS_OPT ,
154+ false ,
155+ ALLOW_RECREATE_CONSTRAINTS_OPT ,
156+ true ));
157+ // check expected results.
158+ assertWithMessage ("Mismatch for section (noDrops)%s" , segmentName )
159+ .that (diff )
160+ .isEqualTo (expectedDiffNoDrops );
148161 }
149162}
0 commit comments