View Javadoc
1   package org.dbunit.ext.postgresql;
2   
3   import static org.assertj.core.api.Assertions.assertThat;
4   
5   import java.io.StringReader;
6   import java.sql.Statement;
7   import java.util.Objects;
8   
9   import org.dbunit.DatabaseEnvironment;
10  import org.dbunit.database.DatabaseConfig;
11  import org.dbunit.database.IDatabaseConnection;
12  import org.dbunit.dataset.IDataSet;
13  import org.dbunit.dataset.ITable;
14  import org.dbunit.dataset.ReplacementDataSet;
15  import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
16  import org.dbunit.operation.DatabaseOperation;
17  import org.junit.jupiter.api.AfterEach;
18  import org.junit.jupiter.api.BeforeEach;
19  import org.junit.jupiter.api.Test;
20  import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
21  import org.xml.sax.InputSource;
22  
23  /**
24   * Integration test proving {@link UuidType}, {@link InetType}, and
25   * {@link CitextType} all bind a real sql {@code NULL} for a null column
26   * value via {@code CLEAN_INSERT}, instead of throwing
27   * {@link NullPointerException} from their PGobject-building helper (issues
28   * 677 and 930).
29   *
30   * <p>{@link GenericEnumType} shares the same fix (see its unit tests) but is
31   * deliberately not exercised here: a custom PostgreSQL enum column is
32   * reported as sql type {@code VARCHAR} (not {@code OTHER}) by
33   * {@code DatabaseMetaData.getColumns()}, so {@link PostgresqlDataTypeFactory}
34   * never selects {@code GenericEnumType} for a real table column in the first
35   * place - a separate, pre-existing defect unrelated to null handling
36   * (issue 933), discovered while writing this test.
37   *
38   * @author Jeff Jensen
39   * @since 3.5.0
40   */
41  @EnabledIfSystemProperty(named = "dbunit.profile", matches = "postgresql")
42  class PostgresqlNullableOtherTypesIT
43  {
44      private IDatabaseConnection _connection;
45      private final String testTable = "nullable_other_types_test";
46      // @formatter:off
47      private static final String xmlData = "<?xml version=\"1.0\"?>" +
48              "<dataset>" +
49              "<NULLABLE_OTHER_TYPES_TEST ID=\"1\" UID=\"08004327-3f6c-4335-9738-0b2bf885cc43\" IP=\"192.168.1.1\" NOTE=\"Hello\" />" +
50              "<NULLABLE_OTHER_TYPES_TEST ID=\"2\" UID=\"[NULL]\" IP=\"[NULL]\" NOTE=\"[NULL]\" />" +
51              "</dataset>";
52      // @formatter:on
53  
54      @BeforeEach
55      protected void setUp() throws Exception
56      {
57          // Load active postgreSQL profile and connection from Maven pom.xml.
58          _connection = DatabaseEnvironment.getInstance().getConnection();
59          try (Statement stat = _connection.getConnection().createStatement())
60          {
61              stat.execute("DROP TABLE IF EXISTS " + testTable + ";");
62              stat.execute("CREATE EXTENSION IF NOT EXISTS citext;");
63              stat.execute("CREATE TABLE " + testTable
64                      + "(ID INTEGER NOT NULL, UID uuid, IP inet, NOTE citext);");
65          }
66          // Mirrors PostgresqlUuidIT/PostgresqlJsonIT: the table isn't visible
67          // to a fresh dataset without reopening the connection.
68          _connection.close();
69          _connection = DatabaseEnvironment.getInstance().getConnection();
70      }
71  
72      @AfterEach
73      protected void tearDown() throws Exception
74      {
75          if (!Objects.isNull(_connection))
76          {
77              try (Statement stat =
78                      _connection.getConnection().createStatement())
79              {
80                  stat.execute("DROP TABLE IF EXISTS " + testTable + ";");
81              } finally
82              {
83                  _connection.close();
84                  _connection = null;
85              }
86          }
87      }
88  
89      @Test
90      void testCleanInsert_withNullUuidInetCitextValues_roundTripsNullWithoutThrowing()
91              throws Exception
92      {
93          assertThat(_connection).as("didn't get a connection.").isNotNull();
94          final DatabaseConfig config = _connection.getConfig();
95          config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
96                  new PostgresqlDataTypeFactory());
97  
98          final ReplacementDataSet dataSet =
99                  new ReplacementDataSet(new FlatXmlDataSetBuilder()
100                         .build(new InputSource(new StringReader(xmlData))));
101         dataSet.addReplacementObject("[NULL]", null);
102         dataSet.setStrictReplacement(true);
103 
104         DatabaseOperation.CLEAN_INSERT.execute(_connection, dataSet);
105 
106         final IDataSet actualDataSet = _connection.createDataSet();
107         final ITable actualTable = actualDataSet.getTable(testTable);
108 
109         assertThat(actualTable.getValue(0, "UID")).as("row 0 UID.")
110                 .isEqualTo("08004327-3f6c-4335-9738-0b2bf885cc43");
111         assertThat(actualTable.getValue(0, "IP")).as("row 0 IP.")
112                 .isEqualTo("192.168.1.1");
113         assertThat(actualTable.getValue(0, "NOTE")).as("row 0 NOTE.")
114                 .isEqualTo("Hello");
115 
116         assertThat(actualTable.getValue(1, "UID"))
117                 .as("row 1 UID should be null.").isNull();
118         assertThat(actualTable.getValue(1, "IP"))
119                 .as("row 1 IP should be null.").isNull();
120         assertThat(actualTable.getValue(1, "NOTE"))
121                 .as("row 1 NOTE should be null.").isNull();
122     }
123 }