/* * Copyright 2015 the original author or authors. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.cloud.stream.module.jdbc; import static org.hamcrest.Matchers.*; import java.util.HashMap; import java.util.List; import java.util.Map; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.test.IntegrationTest; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.cloud.stream.annotation.Bindings; import org.springframework.cloud.stream.messaging.Sink; import org.springframework.tuple.Tuple; import org.springframework.tuple.TupleBuilder; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.messaging.support.MessageBuilder; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * Integration Tests for JdbcSink. Uses hsqldb as a (real) embedded DB. * * @author Eric Bottard * @author Thomas Risberg */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = {JdbcSinkApplication.class, EmbeddedDataSourceConfiguration.class}) @IntegrationTest({"server.port=-1"}) @DirtiesContext public abstract class JdbcSinkIntegrationTests { @Autowired @Bindings(JdbcSinkConfiguration.class) protected Sink channels; @Autowired protected JdbcOperations jdbcOperations; @IntegrationTest public static class DefaultBehavior extends JdbcSinkIntegrationTests { @Test public void testInsertion() { Payload sent = new Payload("hello", 42); channels.input().send(MessageBuilder.withPayload(sent).build()); String result = jdbcOperations.queryForObject("select payload from messages", String.class); Assert.assertThat(result, is("hello42")); } } @IntegrationTest(value = "columns=a,b") public static class SimpleMappingTests extends JdbcSinkIntegrationTests { @Test public void testInsertion() { Payload sent = new Payload("hello", 42); channels.input().send(MessageBuilder.withPayload(sent).build()); Payload result = jdbcOperations.query("select a, b from messages", new BeanPropertyRowMapper<>(Payload.class)).get(0); Assert.assertThat(result, Matchers.samePropertyValuesAs(sent)); } } // annotation below relies on java.util.Properties so backslash needs to be doubled @IntegrationTest(value = "columns=a: a.substring(0\\\\, 4), b: b + 624") public static class SpELTests extends JdbcSinkIntegrationTests { @Test public void testInsertion() { Payload sent = new Payload("hello", 42); channels.input().send(MessageBuilder.withPayload(sent).build()); Payload expected = new Payload("hell", 666); Payload result = jdbcOperations.query("select a, b from messages", new BeanPropertyRowMapper<>(Payload.class)).get(0); Assert.assertThat(result, Matchers.samePropertyValuesAs(expected)); } } @IntegrationTest(value = {"columns=a,b"}) public static class VaryingInsertTests extends JdbcSinkIntegrationTests { @Test public void testInsertion() { Payload a = new Payload("hello", 42); Payload b = new Payload("world", 12); Payload c = new Payload("bonjour", null); Payload d = new Payload(null, 22); channels.input().send(MessageBuilder.withPayload(a).build()); channels.input().send(MessageBuilder.withPayload(b).build()); channels.input().send(MessageBuilder.withPayload(c).build()); channels.input().send(MessageBuilder.withPayload(d).build()); List<Payload> result = jdbcOperations.query("select a, b from messages", new BeanPropertyRowMapper<>(Payload.class)); Assert.assertThat(result, containsInAnyOrder( samePropertyValuesAs(a), samePropertyValuesAs(b), samePropertyValuesAs(c), samePropertyValuesAs(d) )); } } @IntegrationTest(value = {"tableName=no_script", "initialize=true", "columns=a,b"}) public static class ImplicitTableCreationTests extends JdbcSinkIntegrationTests { @Test public void testInsertion() { Payload sent = new Payload("hello", 42); channels.input().send(MessageBuilder.withPayload(sent).build()); Payload result = jdbcOperations.query("select a, b from no_script", new BeanPropertyRowMapper<>(Payload.class)).get(0); Assert.assertThat(result, Matchers.samePropertyValuesAs(sent)); } } @IntegrationTest(value = {"tableName=foobar", "initialize=classpath:explicit-script.sql", "columns=a,b"}) public static class ExlicitTableCreationTests extends JdbcSinkIntegrationTests { @Test public void testInsertion() { Payload sent = new Payload("hello", 42); channels.input().send(MessageBuilder.withPayload(sent).build()); Payload result = jdbcOperations.query("select a, b from foobar", new BeanPropertyRowMapper<>(Payload.class)).get(0); Assert.assertThat(result, Matchers.samePropertyValuesAs(sent)); } } @IntegrationTest(value = {"columns=a,b"}) public static class MapPayloadInsertTests extends JdbcSinkIntegrationTests { @Test public void testInsertion() { NamedParameterJdbcOperations namedParameterJdbcOperations = new NamedParameterJdbcTemplate(jdbcOperations); Map<String, Object> mapA = new HashMap<>(); mapA.put("a", "hello1"); mapA.put("b", 42); Map<String, Object> mapB = new HashMap<>(); mapB.put("a", "hello2"); mapB.put("b", null); Map<String, Object> mapC = new HashMap<>(); mapC.put("a", "hello3"); channels.input().send(MessageBuilder.withPayload(mapA).build()); channels.input().send(MessageBuilder.withPayload(mapB).build()); channels.input().send(MessageBuilder.withPayload(mapC).build()); Assert.assertThat(namedParameterJdbcOperations.queryForObject( "select count(*) from messages where a = :a and b = :b", mapA, Integer.class), is(1)); Assert.assertThat(namedParameterJdbcOperations.queryForObject( "select count(*) from messages where a = :a and b IS NULL", mapB, Integer.class), is(1)); Assert.assertThat(namedParameterJdbcOperations.queryForObject( "select count(*) from messages where a = :a and b IS NULL", mapC, Integer.class), is(1)); } } @IntegrationTest(value = {"columns=a,b"}) public static class TuplePayloadInsertTests extends JdbcSinkIntegrationTests { @Test public void testInsertion() { Tuple tupleA = TupleBuilder.tuple().of("a", "hello1", "b", 42); Tuple tupleB = TupleBuilder.tuple().of("a", "hello2", "b", null); Tuple tupleC = TupleBuilder.tuple().of("a", "hello3"); channels.input().send(MessageBuilder.withPayload(tupleA).build()); channels.input().send(MessageBuilder.withPayload(tupleB).build()); channels.input().send(MessageBuilder.withPayload(tupleC).build()); Assert.assertThat(jdbcOperations.queryForObject( "select count(*) from messages where a = ? and b = ?", Integer.class, tupleA.getString("a"), tupleA.getInt("b")), is(1)); Assert.assertThat(jdbcOperations.queryForObject( "select count(*) from messages where a = ? and b IS NULL", Integer.class, tupleB.getString("a")), is(1)); Assert.assertThat(jdbcOperations.queryForObject( "select count(*) from messages where a = ? and b IS NULL", Integer.class, tupleC.getString("a")), is(1)); } } @IntegrationTest(value = {"columns=a,b"}) public static class JsonStringPayloadInsertTests extends JdbcSinkIntegrationTests { @Test public void testInsertion() { String stringA = "{\"a\": \"hello1\", \"b\": 42}"; String stringB = "{\"a\": \"hello2\", \"b\": null}"; String stringC = "{\"a\": \"hello3\"}"; channels.input().send(MessageBuilder.withPayload(stringA).build()); channels.input().send(MessageBuilder.withPayload(stringB).build()); channels.input().send(MessageBuilder.withPayload(stringC).build()); Assert.assertThat(jdbcOperations.queryForObject( "select count(*) from messages where a = ? and b = ?", Integer.class, "hello1", 42), is(1)); Assert.assertThat(jdbcOperations.queryForObject( "select count(*) from messages where a = ? and b IS NULL", Integer.class, "hello2"), is(1)); Assert.assertThat(jdbcOperations.queryForObject( "select count(*) from messages where a = ? and b IS NULL", Integer.class, "hello3"), is(1)); } } public static class Payload { private String a; private Integer b; public Payload() { } public Payload(String a, Integer b) { this.a = a; this.b = b; } public String getA() { return a; } public Integer getB() { return b; } public void setA(String a) { this.a = a; } public void setB(Integer b) { this.b = b; } @Override public String toString() { return a + b; } } }