All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jars.nosqlunit-documentation.0.10.0.source-code.redis.xml Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
<?xml version="1.0" encoding="UTF-8"?>
<chapter version="5.0" xml:id="redis" xmlns="http://docbook.org/ns/docbook"
	xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude"
	xmlns:svg="http://www.w3.org/2000/svg" xmlns:m="http://www.w3.org/1998/Math/MathML"
	xmlns:html="http://www.w3.org/1999/xhtml" xmlns:db="http://docbook.org/ns/docbook">

	<title>Redis Engine</title>

	<section>
		<title>Redis</title>

		<para>
			<application>Redis</application>
			is an open source, advanced key-value store. It is often referred to
			as a data structure server since keys can contain strings, hashes,
			lists, sets and sorted sets.
		</para>

		<para>
			<emphasis role="bold">NoSQLUnit</emphasis>
			supports
			<emphasis>Redis</emphasis>
			by using next classes:
		</para>
		<para>
			<table border="1">
				<caption>Lifecycle Management Rules</caption>

				<tr>
					<td>Embedded</td>
					<td>
						<classname>com.lordofthejars.nosqlunit.redis.EmbeddedRedis
						</classname>
					</td>
				</tr>
				<tr>
					<td>Managed</td>

					<td>
						<classname>com.lordofthejars.nosqlunit.redis.ManagedRedis
						</classname>
					</td>
				</tr>
			</table>
		</para>
		<para>
			<table border="1">
				<caption>Manager Rule</caption>

				<tr>
					<td>NoSQLUnit Management</td>

					<td>
						<classname>com.lordofthejars.nosqlunit.redis.RedisRule
						</classname>
					</td>
				</tr>
			</table>
		</para>

		<section>
			<title>Maven Setup</title>

			<para>
				To use
				<emphasis role="bold">NoSQLUnit</emphasis>
				with
				<application>Redis</application>
				you only need to add next
				dependency:
			</para>

			<example xml:id="conf.nosqlunit_redis_dep">
				<title>NoSqlUnit Maven Repository</title>

				<programlisting language="xml"><![CDATA[<dependency>
	<groupId>com.lordofthejars</groupId>
	<artifactId>nosqlunit-redis</artifactId>
	<version>${version.nosqlunit}</version>
</dependency>]]></programlisting>
			</example>
		</section>

		<section>
			<title>Dataset Format</title>

			<para>
				Default dataset file format in
				<emphasis>Redis</emphasis>
				module is json.
			</para>

			<para>
				Datasets must have next
				<link linkend="ex.redis_dataset">
					format
				</link>
				:
			</para>

			<example xml:id="ex.redis_dataset">
				<title>Example of Redis Dataset</title>

				<programlisting language="json"><![CDATA[{
"data":[
			{"simple": [
				{
					"key":"key1", 
					"value":"value1"
				}
				]
			},
      		{"list": [{
              			"key":"key3",
              			"values":[
                  			{"value":"value3"},
                  			{"value":"value4"}
              			]
					  }]
      		},
      		
     		{"sortset": [{
                     "key":"key4",
                     "values":[
                           {"score":2, "value":"value5" },{"score":3, "value":1 }, {"score":1, "value":"value6" }]
                 }]
      		}, 
      		{"hash": [
      					{
      						"key":"user",
      						"values":[
      							{"field":"name", "value":"alex"},
      							{"field":"password", "value":"alex"}
      						]
      					}
      				]
      		},
      		{"set":[{
              			"key":"key3",
              			"values":[
                  			{"value":"value3"},
                  			{"value":"value4"}
              			]
					  }]
      		}
]
}]]></programlisting>
			</example>

			<para>
				Root element must be called
				<emphasis>data</emphasis>
				, and then depending on kind of structured data we need to store,
				one or more of next elements should appear. Note that key field is
				used to set the key of the element, and value field is used to set a
				value.
			</para>

			<para>
				<itemizedlist>
					<listitem>
						<para>
							<emphasis>simple</emphasis>
							:
							In case we want to store simple key/value elements. This
							element
							will contain an array of key/value entries.
						</para>
					</listitem>
					<listitem>
						<para>
							<emphasis>list</emphasis>
							:
							In case we want to store a key with a list of values. This
							element
							contain a
							<emphasis>key</emphasis>
							field
							for key name and
							<emphasis>values</emphasis>
							field
							with an array of values.
						</para>
					</listitem>
					<listitem>
						<para>
							<emphasis>set</emphasis>
							In case we want to store a key within a set (no duplicates
							allowed). Structure is the same as list element.
						</para>
					</listitem>
					<listitem>
						<para>
							<emphasis>sortset</emphasis>
							:
							In case we want to store a key within a sorted set. This element
							contain the key, and an array of values, which each one, apart
							from value field, also contain
							<emphasis>score</emphasis>
							field of type Number, to set the order into sorted set.
						</para>
					</listitem>
					<listitem>
						<para>
							<emphasis>hash</emphasis>
							:
							In case we want to store a key within a map of field/value. In
							this case
							<emphasis>field</emphasis>
							element set the field name, and
							<emphasis>value</emphasis>
							set the
							value of that field.
						</para>
					</listitem>
				</itemizedlist>
			</para>

		</section>


		<section>
			<title>Getting Started</title>

			<section>
				<title>Lifecycle Management Strategy</title>

				<para>
					First step is defining which lifecycle management strategy is
					required for your tests. Depending on kind of test you are
					implementing (unit test, integration test, deployment test, ...)
					you will require an embedded approach, managed approach or remote
					approach.
				</para>

				<section>
					<title>Embedded Lifecycle</title>
					<para>
						To configure
						<emphasis role="bold">embedded</emphasis>
						approach you should only instantiate next
						<link linkend="program.redis_embedded_conf">rule</link>
						:
					</para>

					<example xml:id="program.redis_embedded_conf">
						<title>Embedded Redis</title>

						<programlisting language="java"><![CDATA[@ClassRule
	public static EmbeddedRedis embeddedRedis = newEmbeddedRedisRule().build();]]></programlisting>
					</example>

					<para>
						By default managed
						<emphasis>Redis</emphasis>
						rule uses next
						default values but can be configured
						programmatically:
					</para>
					<table>
						<caption>Default Embedded Values</caption>
						<tr>
							<td>
								Target path
							</td>
							<td>
								This is the directory where
								<emphasis>Redis</emphasis>
								embedded instance is started and is
								<constant>target/redis-test-data/impermanent-db</constant>
								.
							</td>
						</tr>
					</table>
					<para>Note that target path is only used as a configuration
						parameter to allow multiple instances of embedded in-memory Redis engine.
					</para>
					<para>For more information about embedded in-memory Redis take a tour to section: <link linkend="advanced.redis_embedded.section">Embedded In-Memory Redis</link></para>
				</section>
				<section>
					<title>Managed Lifecycle</title>
					<para>
						To configure
						<emphasis role="bold">managed</emphasis>
						approach you should only instantiate next
						<link linkend="program.redis_managed_conf">rule</link>
						:
					</para>

					<example xml:id="program.redis_managed_conf">
						<title>Managed Redis</title>

						<programlisting language="java"><![CDATA[@ClassRule
public static ManagedRedis managedRedis = newManagedRedisRule().redisPath("/opt/redis-2.4.16").build();]]></programlisting>
					</example>

					<para>
						By default managed
						<emphasis>Redis</emphasis>
						rule uses next
						default values but can be configured
						programmatically:
					</para>

					<para>
						<table>
							<caption>Default Managed Values</caption>
							<tr>
								<td>
									Target path
								</td>
								<td>
									This is the directory where
									<emphasis>Redis</emphasis>
									server is started and is
									<constant>target/redis-temp</constant>
									.
								</td>
							</tr>
							<tr>
								<td>
									RedisPath
								</td>
								<td>
									<emphasis>Cassandra</emphasis>
									installation directory which by default is
									retrieved from
									<varname>REDIS_HOME</varname>
									system environment
									variable.
								</td>
							</tr>
							<tr>
								<td>
									Port
								</td>
								<td>
									By default port used is 6379. If port is changed in
									<emphasis>Redis</emphasis>
									configuration file, this port should be configured too here.
								</td>
							</tr>
							<tr>
								<td>
									Configuration File
								</td>
								<td>
									By default
									<emphasis>Redis</emphasis>
									can work with no configuration file, it uses default values,
									but if we need to start
									<emphasis>Redis</emphasis>
									with an specific configuration file located in any directory
									file path should be set.
								</td>
							</tr>
						</table>
					</para>
				</section>
				<section>
					<title>Remote Lifecycle</title>
					<para>
						Configuring
						<emphasis role="bold">remote</emphasis>
						approach
						does not require any special rule because you (or System
						like
						<application>Maven</application>
						) is the responsible of starting and
						stopping the server. This mode
						is used in deployment tests where you
						are testing your application
						on real environment.
					</para>
				</section>
			</section>

			<section>
				<title>Configuring Redis Connection</title>

				<para>
					Next step is configuring
					<emphasis role="bold">Redis</emphasis>
					rule in charge of maintaining
					<emphasis>Redis</emphasis>
					store into known state by inserting and deleting defined
					datasets.
					You must register
					<classname>RedisRule</classname>
					<emphasis>JUnit</emphasis>
					rule class, which
					requires a configuration parameter with
					information like host,
					port, or cluster name.
				</para>

				<para>To make developer's life easier and code more readable, a
					fluent
					interface can be used to create these configuration objects.
					Three
					different kind of configuration builders exist.
				</para>
				
				<section>
					<title>Embedded Connection</title>
					<para>
						The first one is for configuring an embedded connection to managed
						<emphasis>Redis</emphasis>
						.
					</para>

					<example xml:id="program.embedded_connection_redis_parameters">
						<title>Redis with embedded configuration</title>

						<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.redis.RedisRule.RedisRuleBuilder.newRedisRule;
						
@Rule
public RedisRule redisRule = newRedisRule().defaultEmbeddedRedis();
						]]></programlisting>
					</example>
				</section>


				<section>
					<title>Managed Connection</title>
					<para>
						Configuring a connection to managed
						<emphasis>Redis</emphasis>
						.
					</para>

					<example xml:id="program.managed_connection_redis_parameters">
						<title>Redis with managed configuration</title>

						<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.redis.ManagedRedisConfigurationBuilder.newManagedRedisConfiguration;
						
@Rule
public RedisRule redisRule = new RedisRule(newManagedRedisConfiguration().build());
						]]></programlisting>
					</example>
					<para>
						Host and port parameters are already configured with default
						parameters of managed lifecycle. If port is changed, this class
						provides a method to set it.
					</para>
				</section>

				<section>
					<title>Remote Connection</title>
					<para>
						Configuring a connection to remote
						<emphasis>Redis</emphasis>
						.
					</para>

					<example xml:id="program.remote_connection_redis_parameters">
						<title>Redis with remote configuration</title>

						<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.redis.RemoteRedisConfigurationBuilder.newRemoteRedisConfiguration;

@Rule
public RedisRule redisRule = new RedisRule(newRemoteRedisConfiguration().host("192.168.1.1").build());]]></programlisting>
					</example>
					<para>
						Port parameter is already configured with default parameter
						of managed lifecycle. If port is changed, this class provides a
						method to set it. Note that host parameter must be specified in
						this case.
					</para>
				</section>

				<section>
					<title>Shard Connection</title>
					<para>Redis connection can also be configured as shard using
						ShardedJedis capabilities.
					</para>
					<example xml:id="program.shard_connection_redis_parameters">
						<title>Redis with remote configuration</title>

						<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.redis.RemoteRedisConfigurationBuilder.newRemoteRedisConfiguration;

@Rule
public RedisRule redisRule = new RedisRule(newShardedRedisConfiguration()
				.shard(host("127.0.0.1"), port(ManagedRedis.DEFAULT_PORT))
					.password("a")
					.timeout(1000)
					.weight(1000)
				.shard(host("127.0.0.1"), port(ManagedRedis.DEFAULT_PORT + 1))
					.password("b")
					.timeout(3000)
					.weight(3000)
				.build());]]></programlisting>
					</example>

					<para>
						Note that only
						<methodparam>host</methodparam>
						and
						<methodparam>port</methodparam>
						is mandatory, the other ones uses default values.
					</para>

					<para>
						<itemizedlist>
							<listitem>
								<para>
									<emphasis>password</emphasis>
									:
									In case repository is protected with password this attribute
									is used as password. Default values is null.
								</para>
							</listitem>
							<listitem>
								<para>
									<emphasis>timeout</emphasis>
									:
									Timeout for shard. By default timeout is set to 2 seconds.
								</para>
							</listitem>
							<listitem>
								<para>
									<emphasis>weight</emphasis>
									:
									The weight of that shard over the other ones. By default is 1.
								</para>
							</listitem>
						</itemizedlist>
					</para>

				</section>

			</section>

			<section>
				<title>Verifying Data</title>
				<para>
					<classname>@ShouldMatchDataSet</classname>
					is also supported for
					<emphasis>Redis</emphasis>
					engine.
				</para>
			</section>

			<section>
				<title>Full Example</title>

				<para>
					To show how to use
					<emphasis role="bold">NoSQLUnit</emphasis>
					with
					<emphasis>Redis</emphasis>
					,
					we are going to create a
					very simple application.
				</para>
				<para>
					<link linkend="program.book_redis_manager">BookManager</link>
					is the business class responsible of inserting new books and
					finding books by their title.
				</para>
				<example xml:id="program.book_redis_manager">
					<title>Book manager with Redis</title>

					<programlisting language="java"><![CDATA[public class BookManager {
	
	private static final String TITLE_FIELD_NAME = "title";
	private static final String NUMBER_OF_PAGES = "numberOfPages";
	
	private Jedis jedis;
	
	public BookManager(Jedis jedis) {
		this.jedis = jedis;
	}
	
	public void insertBook(Book book) {
		
		Map<String, String> fields = new HashMap<String, String>();
		
		fields.put(TITLE_FIELD_NAME, book.getTitle());
		fields.put(NUMBER_OF_PAGES, Integer.toString(book.getNumberOfPages()));
		
		jedis.hmset(book.getTitle(), fields);
	}

	public Book findBookByTitle(String title) {
		
		Map<String, String> fields = jedis.hgetAll(title);
		return new Book(fields.get(TITLE_FIELD_NAME), Integer.parseInt(fields.get(NUMBER_OF_PAGES)));
		
	}
	
}]]></programlisting>
				</example>

				<para>
					And now one integration test is written:
				</para>

				<example xml:id="program.book_redis_integration">
					<title>Redis with managed configuration</title>

					<programlisting language="java"><![CDATA[import static com.lordofthejars.nosqlunit.redis.RedisRule.RedisRuleBuilder.newRedisRule;
import static com.lordofthejars.nosqlunit.redis.ManagedRedis.ManagedRedisRuleBuilder.newManagedRedisRule;

import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;

import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;

import redis.clients.jedis.Jedis;

import com.lordofthejars.nosqlunit.annotation.UsingDataSet;
import com.lordofthejars.nosqlunit.core.LoadStrategyEnum;
import com.lordofthejars.nosqlunit.demo.model.Book;
import com.lordofthejars.nosqlunit.redis.ManagedRedis;
import com.lordofthejars.nosqlunit.redis.RedisRule;

public class WhenYouFindABook {

	static {
		System.setProperty("REDIS_HOME", "/opt/redis-2.4.16");
	}

	@ClassRule
	public static ManagedRedis managedRedis = newManagedRedisRule().build();

	@Rule
	public RedisRule redisRule = newRedisRule().defaultManagedRedis();
	
	@Test
	@UsingDataSet(locations="book.json", loadStrategy=LoadStrategyEnum.CLEAN_INSERT)
	public void book_should_be_returned_if_title_is_in_database() {
		
		BookManager bookManager = new BookManager(new Jedis("localhost"));
		Book findBook = bookManager.findBookByTitle("The Hobbit");
		
		assertThat(findBook, is(new Book("The Hobbit", 293)));
		
	}

}]]></programlisting>
				</example>

				<para>And dataset used is:
				</para>
				<example xml:id="program.expected_redis_file">
					<title>book.json Redis file</title>

					<programlisting language="json"><![CDATA[{
"data":[	
      		{"hash": [
      					{
      						"key":"The Hobbit",
      						"values":[
      							{"field":"title", "value":"The Hobbit"},
      							{"field":"numberOfPages", "value":"293"}
      						]
      					}
      				]
      		}
]
}]]></programlisting>
				</example>

			</section>


		</section>

	</section>


</chapter>




© 2015 - 2025 Weber Informatics LLC | Privacy Policy