Compare commits

...

51 Commits

Author SHA1 Message Date
Jon Chambers
52cac449aa [maven-release-plugin] prepare for next development iteration
Some checks failed
Service CI / build (macos-latest) (push) Has been cancelled
Service CI / build (ubuntu-latest) (push) Has been cancelled
2024-10-21 11:08:34 -04:00
Jon Chambers
7515aa3653 [maven-release-plugin] prepare release 0.9.1
Some checks failed
Service CI / build (macos-latest) (push) Has been cancelled
Service CI / build (ubuntu-latest) (push) Has been cancelled
2024-10-21 11:08:31 -04:00
Chris Eager
1058eb0d03 Throw EmbeddedRedisException if server fails to start 2024-10-18 15:45:48 -05:00
Jon Chambers
596e1e4f55 Update to commons-io 2.17.0 2024-10-07 12:27:56 -04:00
Jon Chambers
ce50da9193 Update version in dependency snippet in README 2024-03-29 11:49:45 -04:00
Jon Chambers
d766a33570 [maven-release-plugin] prepare for next development iteration 2024-03-29 11:46:32 -04:00
Jon Chambers
9ebccb7ad8 [maven-release-plugin] prepare release 0.9.0
Some checks failed
Service CI / build (ubuntu-latest) (push) Has been cancelled
Service CI / build (macos-latest) (push) Has been cancelled
2024-03-29 11:46:30 -04:00
Chris Eager
8145f151d6 Update Maven plugins 2024-03-26 15:00:42 -05:00
Chris Eager
4e0f1416c3 Update actions/checkout and actions/setup-java to 4.x 2024-02-29 11:45:02 -06:00
Chris Eager
48820c03a4 Update README.md for 0.9.0 2024-02-27 09:51:29 -06:00
Chris Eager
06b2938e6b Update binaries to Redis 7.0.15 2024-02-27 09:51:29 -06:00
Chris Eager
2beaab3fab Update various dependencies 2024-02-27 09:51:29 -06:00
Chris Eager
e22d710cec Update next release to 0.9.0 2024-02-27 09:51:29 -06:00
Jon Chambers
10c7f4478a Update to the latest Nexus staging plugin 2022-06-02 22:46:53 -04:00
Jon Chambers
b36c69a158 [maven-release-plugin] prepare for next development iteration 2022-06-02 17:03:54 -04:00
Jon Chambers
455e42ee36 [maven-release-plugin] prepare release 0.8.3
Some checks failed
Service CI / build (macos-latest) (push) Has been cancelled
Service CI / build (ubuntu-latest) (push) Has been cancelled
2022-06-02 17:03:52 -04:00
Jon Chambers
7acd95ac35 Update README for 0.8.3 2022-06-02 17:01:00 -04:00
Jon Chambers
2aee2439c3 Update included binaries to 6.2.7, statically-linked with openssl 2022-06-02 15:47:33 -04:00
Jon Chambers
afc9c99a11 Link against OpenSSL instead of LibreSSL to avoid config file incompatibility issues 2022-06-02 15:47:33 -04:00
Jon Chambers
14b8fa7cd0 Update to Alpine 3.16 and Redis 6.2.7 2022-06-02 15:47:33 -04:00
Jon Chambers
e5bab4e725 Update paths and build instructions for macOS builds 2022-06-02 15:39:08 -04:00
Jon Chambers
5304acbcd7 Build linux binaries with docker buildx 2022-06-02 15:27:30 -04:00
Chris Eager
d6687257c5 prepare for next development iteration 2022-01-27 14:13:36 -08:00
Chris Eager
2add5ed94d prepare release 0.8.2
Some checks failed
Service CI / build (macos-latest) (push) Has been cancelled
Service CI / build (ubuntu-latest) (push) Has been cancelled
2022-01-27 14:12:49 -08:00
Chris Eager
fab79ea41c Update README for 0.8.2 2022-01-27 14:12:20 -08:00
Chris Eager
445a8e67e4
Support arm64/aarch64 Linux and Apple Silicon
- remove references to 32 bit macos/darwin
- normalize Redis server file names
- update `build-server-binaries.sh` to statically link openssl on macOS
- correctly detect macOS and Unix architectures

Co-authored-by: Nathan J Mehl <n@oden.io>
2022-01-11 10:35:00 -08:00
Chris Eager
d8f71db407
Add TLS support; update Redis to 6.2.6 2022-01-10 18:07:51 -08:00
Chris Eager
2021575782 Use actions/setup-java@v2 caching 2021-10-21 10:21:49 -07:00
Chris Eager
941289c257 Add macos to test matrix 2021-10-21 10:21:49 -07:00
Jon Chambers
f47dcc1908 [maven-release-plugin] prepare for next development iteration 2020-07-02 18:24:41 -04:00
Jon Chambers
246234b750 [maven-release-plugin] prepare release 0.8.1
Some checks failed
Service CI / build (push) Has been cancelled
2020-07-02 18:24:35 -04:00
Jon Chambers
92aa9acaec Update the README for 0.8.1. 2020-07-02 18:23:42 -04:00
Jon Chambers
145685ea2e Add an action for testing on new pull requests. 2020-07-02 18:14:31 -04:00
Jon Chambers
5a92491a58 Use statically-linked Redis binaries. 2020-07-02 18:12:25 -04:00
Jon Chambers
71b1d465fb Build server binaries via a Docker container. 2020-07-02 18:12:25 -04:00
Jon Chambers
ce607d21a8 Drop explicit Maven version prerequisites. 2020-07-02 18:09:40 -04:00
Jon Chambers
c166319dcf Update to Mockito 3.3.3. 2020-07-02 18:09:40 -04:00
Jon Chambers
2f501f8a35 Drop Spring Data tests. 2020-07-02 18:09:40 -04:00
Jon Chambers
a8f9f7f1e9 Drop logging. 2020-07-02 18:09:40 -04:00
Jon Chambers
b9c0d4c6fd Update to Commons IO 2.7. 2020-07-02 18:09:40 -04:00
Jon Chambers
c78cd194ba Drop the separate release script (Maven has this covered). 2020-07-01 09:33:36 -04:00
Jon Chambers
8f9d59bf5f Further simplify the POM and update plugins. 2020-07-01 09:33:12 -04:00
Jon Chambers
a5303a8c0e Simplify Javadoc config. 2020-06-30 15:49:41 -04:00
Jon Chambers
fe10288504 [maven-release-plugin] prepare for next development iteration 2020-06-30 11:58:57 -04:00
Jon Chambers
2a5b829fdc [maven-release-plugin] prepare release 0.8.0 2020-06-30 11:58:50 -04:00
Jon Chambers
328d713ff1 Pare down and update the pom. 2020-06-30 11:57:55 -04:00
Jon Chambers
7b44468cfd Drop Jacoco. 2020-06-30 11:48:23 -04:00
Jon Chambers
fbc58c6673 Update the README. 2020-06-30 11:48:23 -04:00
Jon Chambers
9b26bc3487 Update to the latest version of Guava. 2020-06-30 11:48:23 -04:00
Jon Chambers
47e8cd409c Move slf4j-simple to test scope. 2020-06-30 11:48:23 -04:00
Jon Chambers
2be104ed87 Update redis-server binaries to 6.0.5. 2020-06-30 11:48:23 -04:00
36 changed files with 776 additions and 467 deletions

23
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: Service CI
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Set up JDK 11
uses: actions/setup-java@9704b39bf258b59bc04b50fa2dd55e9ed76b47a8 # v4.1.0
with:
java-version: 11
distribution: 'temurin'
cache: 'maven'
- name: Build with Maven
run: mvn -e -B test

102
README.md
View File

@ -5,22 +5,7 @@ Redis embedded server for Java integration testing
Fork Notes
==============
This repository clones from [kstyrc](https://github.com/kstyrc/embedded-redis) original repository.
The aim is to release some long waiting fixes.
**Source Website:** *[github.com/ozimov/embedded-redis](http://github.com/ozimov/embedded-redis/)*<br />
**Latest Release:** *0.7.3* <br />
**Latest Artifact:** *it.ozimov:embedded-redis* <br />
**Continuous Integration:** <br />
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/it.ozimov/embedded-redis/badge.svg)](https://maven-badges.herokuapp.com/maven-central/it.ozimov/embedded-redis)
<br />
[![Build Status](https://travis-ci.org/ozimov/embedded-redis.svg?branch=master)](https://travis-ci.org/ozimov/embedded-redis)
[![codecov.io](https://codecov.io/github/ozimov/embedded-redis/coverage.svg?branch=master)](https://codecov.io/github/ozimov/embedded-redis?branch=master)
[![Codacy Badge](https://api.codacy.com/project/badge/grade/7a4364b93df6473fb18a597e900edceb)](https://www.codacy.com/app/roberto-trunfio/embedded-redis)
![codecov.io](https://codecov.io/github/ozimov/embedded-redis/branch.svg?branch=master)
This repository is a fork of https://github.com/ozimov/embedded-redis, which is in turn a fork of https://github.com/kstyrc/embedded-redis. We've updated the embedded Redis binaries to version 7.0.15 so we can write tests that use recent Redis features without imposing dependencies that are not well-encapsulated by a single Maven/Gradle build.
Maven dependency
==============
@ -28,9 +13,9 @@ Maven dependency
Maven Central:
```xml
<dependency>
<groupId>it.ozimov</groupId>
<groupId>org.signal</groupId>
<artifactId>embedded-redis</artifactId>
<version>0.7.3</version>
<version>0.9.0</version>
</dependency>
```
@ -53,10 +38,11 @@ RedisServer redisServer = new RedisServer("/path/to/your/redis", 6379);
// 2) given os-independent matrix
RedisExecProvider customProvider = RedisExecProvider.defaultProvider()
.override(OS.UNIX, "/path/to/unix/redis")
.override(OS.WINDOWS, Architecture.x86, "/path/to/windows/redis")
.override(OS.Windows, Architecture.x86_64, "/path/to/windows/redis")
.override(OS.MAC_OS_X, Architecture.x86, "/path/to/macosx/redis")
.override(OS.MAC_OS_X, Architecture.x86_64, "/path/to/macosx/redis")
.override(OS.UNIX, Architecture.x86_64, "/path/to/unix/redis.x86_64")
.override(OS.UNIX, Architecture.arm64, "/path/to/unix/redis.arm64")
.override(OS.UNIX, Architecture.x86, "/path/to/unix/redis.i386")
.override(OS.MAC_OS_X, Architecture.x86_64, "/path/to/macosx/redis-x86_64")
.override(OS.MAC_OS_X, Architecture.arm64, "/path/to/macosx/redis.arm64")
RedisServer redisServer = new RedisServer(customProvider, 6379);
```
@ -154,32 +140,80 @@ second replication group on ```6387, 6379``` and third replication group on ephe
Redis version
==============
When not provided with the desired redis executable, RedisServer runs os-dependent executable enclosed in jar. Currently is uses:
- Redis 2.8.19 in case of Linux/Unix
- Redis 2.8.19 in case of OSX
- Redis 2.8.19 in case of Windows: https://github.com/MSOpenTech/redis/releases/tag/win-2.8.19
By default, RedisServer runs an OS-specific executable enclosed in in the `embedded-redis` jar. The jar includes:
However, you should provide RedisServer with redis executable if you need specific version.
- Redis 7.0.15 for Linux/Unix (i386, x86_64 and arm64)
- Redis 7.0.15 for macOS (x86_64 and arm64e AKA Apple Silicon)
The enclosed binaries are built from source from the [`7.0.15` tag](https://github.com/redis/redis/releases/tag/7.0.15) in the official Redis repository. The Linux and Darwin/macOS binaries are statically-linked amd64 and x86 executables built using the [build-server-binaries.sh](src/main/docker/build-server-binaries.sh) script included in this repository at `/src/main/docker`. Windows binaries are not included because Windows is not officially supported by Redis.
Note: the `build-server-binaries.sh` script attempts to build all of the above noted OS and architectures, which means that it expects the local Docker daemon to support all of them. Docker Desktop on macOS and Windows supports multi-arch builds out of the box; Docker on Linux may require [additional configuration](https://docs.docker.com/buildx/working-with-buildx/).
Callers may provide a path to a specific `redis-server` executable if needed.
License
==============
Licensed under the Apache License, Version 2.0
The included Redis binaries are covered by [Rediss license](https://github.com/redis/redis/blob/4930d19e70c391750479951022e207e19111eb55/COPYING):
> Copyright (c) 2006-2020, Salvatore Sanfilippo
> All rights reserved.
>
> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
>
> * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
> * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
> * Neither the name of Redis nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
>
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Contributors
==============
* Krzysztof Styrc ([@kstyrc](http://github.com/kstyrc))
* Piotr Turek ([@turu](http://github.com/turu))
* anthonyu ([@anthonyu](http://github.com/anthonyu))
* Artem Orobets ([@enisher](http://github.com/enisher))
* Sean Simonsen ([@SeanSimonsen](http://github.com/SeanSimonsen))
* Rob Winch ([@rwinch](http://github.com/rwinch))
* Krzysztof Styrc ([@kstyrc](https://github.com/kstyrc))
* Piotr Turek ([@turu](https://github.com/turu))
* anthonyu ([@anthonyu](https://github.com/anthonyu))
* Artem Orobets ([@enisher](https://github.com/enisher))
* Sean Simonsen ([@SeanSimonsen](https://github.com/SeanSimonsen))
* Rob Winch ([@rwinch](https://github.com/rwinch))
* Jon Chambers ([@jchambers](https://github.com/jchambers))
* Chris Eager ([@eager](https://github.com/eager))
Changelog
==============
### 0.9.0
* Updated to Redis 7.0.15
* Updated Guava to 33
* Updated JUnit to 4.13.2
### 0.8.3
* Updated to Redis 6.2.7
* Statically link Linux binaries with OpenSSL instead of LibreSSL to avoid `openssl.cnf` incompatibilities
### 0.8.2
* Updated to Redis 6.2.6
* Added native support for Apple Silicon (darwin/arm64) and Linux aarch64
* Compiled Redis servers with TLS support
### 0.8.1
* Include statically-linked Redis binaries
* Update still more dependencies
### 0.8
* Updated to Redis 6.0.5
* Dropped support for Windows
* Updated to Guava 29
### 0.7
* Updated dependencies
* Fixed an incorrect maximum memory setting
* Add support for more Redis versions
* Bind to 127.0.0.1 by default
* Clean up gracefully at JVM exit
### 0.6
* Support JDK 6 +

327
pom.xml
View File

@ -1,14 +1,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>it.ozimov</groupId>
<groupId>org.signal</groupId>
<artifactId>embedded-redis</artifactId>
<packaging>jar</packaging>
<version>0.7.4-SNAPSHOT</version>
<version>0.9.2-SNAPSHOT</version>
<name>embedded-redis</name>
<description>Redis embedded server for Java integration testing.
Project forked from https://github.com/kstyrc/embedded-redis</description>
<url>https://github.com/ozimov/embedded-redis</url>
<description>Redis embedded server for Java integration testing.</description>
<url>https://github.com/signalapp/embedded-redis</url>
<licenses>
<license>
@ -19,16 +18,16 @@
</licenses>
<scm>
<url>https://github.com/ozimov/embedded-redis</url>
<connection>scm:git:https://github.com/ozimov/embedded-redis.git</connection>
<developerConnection>scm:git:https://github.com/ozimov/embedded-redis.git</developerConnection>
<tag>embedded-redis-0.7.2</tag>
</scm>
<url>https://github.com/signalapp/embedded-redis</url>
<connection>scm:git:https://github.com/signalapp/embedded-redis.git</connection>
<developerConnection>scm:git:git@github.com:signalapp/embedded-redis.git</developerConnection>
<tag>0.9.1</tag>
</scm>
<developers>
<developer>
<name>Krzysztof Styrc</name>
<email>kstyrc@gmail.com</email>
<name>Jon Chambers</name>
<email>jon@signal.org</email>
</developer>
</developers>
@ -40,67 +39,38 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
<version>33.0.0-jre</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
<version>2.17.0</version>
</dependency>
<!-- TEST DEPENDENCIES -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.2</version>
<!-- incompatible with 2.9.0 and up: https://github.com/ozimov/embedded-redis/pull/4 -->
<version>2.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.0.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<prerequisites>
<maven>3.0.4</maven>
</prerequisites>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
@ -116,182 +86,129 @@
</resource>
</resources>
<plugins>
<!-- MAVEN SUREFIRE + FAILSAFE -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
<!-- Partially works for Lombok -->
<configuration>
<excludes>
<exclude>**/config/**</exclude>
<exclude>**/model/**</exclude>
<exclude>**/item/**</exclude>
</excludes>
</configuration>
<version>3.2.5</version>
</plugin>
<!--Deploy plugins -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.3</version>
<configuration>
<generateBackupPoms>false</generateBackupPoms>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<version>1.9.5</version>
<configuration>
<pushChanges>false</pushChanges>
<tag>${project.version}</tag>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>disable-java8-doclint</id>
<activation>
<jdk>[1.8,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
<configuration>
<source>8</source>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.13</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>copy-test-certs</id>
<phase>process-test-resources</phase>
<goals>
<goal>testResources</goal>
</goals>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
<resources>
<resource>
<directory>${project.basedir}/src/test/bash/tests/tls</directory>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<reporting>
<plugins>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.3</version>
<reportSets>
<reportSet>
<reports>
<report>dependency-updates-report</report>
<report>plugin-updates-report</report>
<report>property-updates-report</report>
</reports>
</reportSet>
</reportSets>
<artifactId>exec-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>generate-test-certificates</id>
<phase>generate-test-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>./gen-test-certs-if-needed.sh</executable>
<workingDirectory>${project.basedir}/src/test/bash</workingDirectory>
<arguments>
<argument>${project.build.testOutputDirectory}</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>cleanup-test-certificates</id>
<phase>process-test-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>./cleanup-test-certs.sh</executable>
<workingDirectory>${project.basedir}/src/test/bash</workingDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</reporting>
<!--DISCLAIMER: use as-->
<!--mvn versions:display-dependency-updates-->
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</build>
</project>

View File

@ -1,58 +0,0 @@
#!/bin/bash
# Deploy maven artifact in current directory into Maven central repository
# using maven-release-plugin goals
###########################################################
###########################################################
cat << "RELEASE"
██████╗ ███████╗██╗ ███████╗ █████╗ ███████╗███████╗
██╔══██╗██╔════╝██║ ██╔════╝██╔══██╗██╔════╝██╔════╝
██████╔╝█████╗ ██║ █████╗ ███████║███████╗█████╗
██╔══██╗██╔══╝ ██║ ██╔══╝ ██╔══██║╚════██║██╔══╝
██║ ██║███████╗███████╗███████╗██║ ██║███████║███████╗
╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝
RELEASE
set -e
mvn --settings ~/.m2/settings.xml scm:check-local-modification
# release
echo "\n----------------------------------------"
echo "When at prompt, type the release version (e.g. from 1.0-SNAPSHOT to 1.0)\n"
mvn --settings ~/.m2/settings.xml versions:set
git commit -am "[Deploy phase] Preparing release"
mvn --settings ~/.m2/settings.xml clean deploy -DskipTests -P release
mvn --settings ~/.m2/settings.xml scm:tag
echo 'Release deployed'
###########################################################
###########################################################
# next development version
cat << "NEXT_ITERATION"
███╗ ██╗███████╗██╗ ██╗████████╗
████╗ ██║██╔════╝╚██╗██╔╝╚══██╔══╝
██╔██╗ ██║█████╗ ╚███╔╝ ██║
██║╚██╗██║██╔══╝ ██╔██╗ ██║
██║ ╚████║███████╗██╔╝ ██╗ ██║
╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═╝
██╗████████╗███████╗██████╗ █████╗ ████████╗██╗ ██████╗ ███╗ ██╗
██║╚══██╔══╝██╔════╝██╔══██╗██╔══██╗╚══██╔══╝██║██╔═══██╗████╗ ██║
██║ ██║ █████╗ ██████╔╝███████║ ██║ ██║██║ ██║██╔██╗ ██║
██║ ██║ ██╔══╝ ██╔══██╗██╔══██║ ██║ ██║██║ ██║██║╚██╗██║
██║ ██║ ███████╗██║ ██║██║ ██║ ██║ ██║╚██████╔╝██║ ╚████║
╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
NEXT_ITERATION
echo "When at prompt, type the SNAPSHOT version (e.g. from 1.0 to 2.0-SNAPSHOT)\n"
mvn --settings ~/.m2/settings.xml versions:set
git commit -am "[Deploy phase] Preparing for next iteration"
# updating origin
git push --force --follow-tags
echo 'Next iteration prepared'

2
src/main/docker/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
redis-server-*
redis-*

View File

@ -0,0 +1,18 @@
ARG ALPINE_VERSION=3.19.1
FROM alpine:${ALPINE_VERSION}
RUN apk add --no-cache gcc musl-dev openssl-dev openssl-libs-static make pkgconfig linux-headers
WORKDIR /build
ARG REDIS_VERSION
ENV REDIS_VERSION=${REDIS_VERSION}
COPY redis-${REDIS_VERSION}.tar.gz /redis-${REDIS_VERSION}.tar.gz
RUN ls -l /
ARG ARCH
RUN tar zxf /redis-${REDIS_VERSION}.tar.gz && \
cd redis-${REDIS_VERSION} && \
make BUILD_TLS='yes' CC='gcc -static' LDFLAGS='-s' MALLOC='libc' && \
mv src/redis-server /build/redis-server-${REDIS_VERSION}-linux-${ARCH}
CMD [ "/bin/sh" ]

View File

@ -0,0 +1,139 @@
#!/bin/bash
set -e
REDIS_VERSION=7.0.15
REDIS_TARBALL="redis-${REDIS_VERSION}.tar.gz"
REDIS_URL="https://download.redis.io/releases/${REDIS_TARBALL}"
echo $ARCH
function copy_openssl_and_remove_dylibs() {
# To make macOS builds more portable, we want to statically link OpenSSL,
# which is not straightforward. To force static compilation, we copy
# the openssl libraries and remove dylibs, forcing static linking
OPENSSL_HOME="${1}"
ARCH=$2
OPENSSL_HOME_COPY="${3}/${ARCH}"
echo "*** Copying openssl libraries for static linking"
cp -RL "${OPENSSL_HOME}" "${OPENSSL_HOME_COPY}"
rm -f "${OPENSSL_HOME_COPY}"/lib/*.dylib
}
if [ "$(dirname ${0})" != "." ]; then
echo "This script must be run from $(dirname ${0}). \`cd\` there and run again"
exit 1
fi
if ! [ -f "${REDIS_TARBALL}" ]; then
curl -o "${REDIS_TARBALL}" "${REDIS_URL}"
fi
all_linux=0
if command -pv docker buildx 2>/dev/null; then
for arch in amd64 arm64 386; do
builder_name="embedded-redis-builder-$RANDOM"
docker buildx create \
--name "$builder_name" \
--platform linux/amd64,linux/arm64,linux/386
docker buildx use "$builder_name"
echo "*** Building redis version ${REDIS_VERSION} for linux-${arch}"
set +e
docker buildx build \
"--platform=linux/${arch}" \
--build-arg "REDIS_VERSION=${REDIS_VERSION}" \
--build-arg "ARCH=${arch}" \
-t "redis-server-builder-${arch}" \
--load \
.
if [[ $? -ne 0 ]]; then
echo "*** ERROR: could not build for linux-${arch}"
continue
fi
set -e
docker buildx rm "$builder_name"
docker run -it --rm \
"--platform=linux/${arch}" \
-v "$(pwd)/":/mnt \
--user "$(id -u):$(id -g)" \
"redis-server-builder-${arch}" \
sh -c "cp /build/redis-server-${REDIS_VERSION}-linux-${arch} /mnt"
((all_linux+=1))
done
else
echo "*** WARNING: No docker command found or docker does not support buildx. Cannot build for linux."
fi
if [[ "${all_linux}" -lt 3 ]]; then
echo "*** WARNING: was not able to build for all linux arches; see above for errors"
fi
# To build for macOS, you must be running this script from a Mac. The script requires that openssl@1.1
# be installed via Homebrew.
#
# To build Redis binaries for both arm64e and x86_64, you'll need to run this script from an arm64e
# Mac with _two_ parallel installations of Homebrew (see
# https://stackoverflow.com/questions/64951024/how-can-i-run-two-isolated-installations-of-homebrew),
# and install openssl@1.1 with each.
if [[ "$(uname -s)" == "Darwin" ]]; then
tar zxf "${REDIS_TARBALL}"
cd "redis-${REDIS_VERSION}"
# temporary directory for openssl libraries for static linking.
# assumes standard Homebrew openssl install:
# - arm64e at /opt/homebrew/opt/openssl@1.1
# - x86_64 at /usr/local/opt/openssl@1.1
OPENSSL_TEMP=$(mktemp -d /tmp/embedded-redis-darwin-openssl.XXXXX)
# build for arm64 on apple silicon
if arch -arm64e true 2>/dev/null; then
if [ -d /opt/homebrew/opt/openssl@1.1 ]; then
copy_openssl_and_remove_dylibs /opt/homebrew/opt/openssl@1.1 arm64e "${OPENSSL_TEMP}"
echo "*** Building redis version ${REDIS_VERSION} for darwin-arm64e (apple silicon)"
make distclean
arch -arm64e make -j3 BUILD_TLS=yes OPENSSL_PREFIX="$OPENSSL_TEMP/arm64e"
mv src/redis-server "../redis-server-${REDIS_VERSION}-darwin-arm64"
else
echo "*** WARNING: openssl@1.1 not found for darwin-arm64e; skipping build"
fi
else
echo "*** WARNING: could not build for darwin-arm64e; you probably want to do this on an apple silicon device"
fi
# build for x86_64 if we're on apple silicon or a recent macos on x86_64
if arch -x86_64 true 2>/dev/null; then
if [ -d /usr/local/opt/openssl@1.1 ]; then
copy_openssl_and_remove_dylibs /usr/local/opt/openssl@1.1 x86_64 "${OPENSSL_TEMP}"
echo "*** Building redis version ${REDIS_VERSION} for darwin-x86_64"
make distclean
arch -x86_64 make -j3 BUILD_TLS=yes OPENSSL_PREFIX="$OPENSSL_TEMP/x86_64"
# x86_64 and amd64 are effectively synonymous; we use amd64 here to match the naming scheme used by Docker builds
mv src/redis-server "../redis-server-${REDIS_VERSION}-darwin-amd64"
else
echo "*** WARNING: openssl@1.1 not found for darwin-x86_64; skipping build"
fi
else
echo "*** WARNING: you are on a version of macos that lacks /usr/bin/arch, you probably do not want this"
exit 1
fi
cd ..
else
echo "*** WARNING: Cannot build for macos/darwin on a $(uname -s) host"
fi
ls -l redis-server-*
echo "*** Moving built binaries to ../resources; you need to handle the rest yourself"
mv redis-server-* ../resources/

View File

@ -1,8 +1,6 @@
package redis.embedded;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import redis.embedded.exceptions.EmbeddedRedisException;
import java.io.*;
@ -14,17 +12,21 @@ import java.util.concurrent.Executors;
abstract class AbstractRedisInstance implements Redis {
private static Log log = LogFactory.getLog(AbstractRedisInstance.class);
protected List<String> args = Collections.emptyList();
private volatile boolean active = false;
private Process redisProcess;
private final int port;
private final int tlsPort;
private ExecutorService executor;
protected AbstractRedisInstance(int port) {
protected AbstractRedisInstance(int port, int tlsPort) {
this.port = port;
this.tlsPort = tlsPort;
}
protected AbstractRedisInstance(int port) {
this(port, 0);
}
public boolean isActive() {
@ -61,20 +63,20 @@ abstract class AbstractRedisInstance implements Redis {
private void awaitRedisServerReady() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(redisProcess.getInputStream()));
try {
StringBuffer outputStringBuffer = new StringBuffer();
StringBuilder outputStringBuilder = new StringBuilder();
String outputLine;
do {
outputLine = reader.readLine();
if (outputLine == null) {
//Something goes wrong. Stream is ended before server was activated.
throw new RuntimeException("Can't start redis server. Check logs for details. Redis process log: " + outputStringBuffer.toString());
// Something is wrong. Stream ended before server was activated.
throw new EmbeddedRedisException("Redis server failed to become ready. Check logs for details. Redis process log: " + outputStringBuilder.toString());
} else {
outputStringBuffer.append("\n");
outputStringBuffer.append(outputLine);
outputStringBuilder.append("\n");
outputStringBuilder.append(outputLine);
}
} while (!outputLine.matches(redisReadyPattern()));
} finally {
IOUtils.closeQuietly(reader);
IOUtils.closeQuietly(reader, null);
}
}
@ -89,14 +91,11 @@ abstract class AbstractRedisInstance implements Redis {
public synchronized void stop() throws EmbeddedRedisException {
if (active) {
log.info("Stopping redis server...");
if (executor != null && !executor.isShutdown()) {
executor.shutdown();
}
redisProcess.destroy();
tryWaitFor();
log.info("Redis exited");
active = false;
}
}
@ -110,7 +109,11 @@ abstract class AbstractRedisInstance implements Redis {
}
public List<Integer> ports() {
return Arrays.asList(port);
return port > 0 ? Collections.singletonList(port) : Collections.emptyList();
}
public List<Integer> tlsPorts() {
return tlsPort > 0 ? Collections.singletonList(tlsPort) : Collections.emptyList();
}
private static class PrintReaderRunnable implements Runnable {
@ -124,7 +127,7 @@ abstract class AbstractRedisInstance implements Redis {
try {
readLines();
} finally {
IOUtils.closeQuietly(reader);
IOUtils.closeQuietly(reader, null);
}
}

View File

@ -12,4 +12,6 @@ public interface Redis {
void stop() throws EmbeddedRedisException;
List<Integer> ports();
List<Integer> tlsPorts();
}

View File

@ -59,6 +59,14 @@ public class RedisCluster implements Redis {
return ports;
}
@Override
public List<Integer> tlsPorts() {
List<Integer> ports = new ArrayList<Integer>();
ports.addAll(sentinelTlsPorts());
ports.addAll(serverTlsPorts());
return ports;
}
public List<Redis> sentinels() {
return Lists.newLinkedList(sentinels);
}
@ -71,6 +79,14 @@ public class RedisCluster implements Redis {
return ports;
}
public List<Integer> sentinelTlsPorts() {
List<Integer> ports = new ArrayList<Integer>();
for(Redis redis : sentinels) {
ports.addAll(redis.tlsPorts());
}
return ports;
}
public List<Redis> servers() {
return Lists.newLinkedList(servers);
}
@ -83,6 +99,14 @@ public class RedisCluster implements Redis {
return ports;
}
public List<Integer> serverTlsPorts() {
List<Integer> ports = new ArrayList<Integer>();
for(Redis redis : servers) {
ports.addAll(redis.tlsPorts());
}
return ports;
}
public static RedisClusterBuilder builder() {
return new RedisClusterBuilder();
}

View File

@ -12,26 +12,26 @@ import java.io.IOException;
import java.util.Map;
public class RedisExecProvider {
private final Map<OsArchitecture, String> executables = Maps.newHashMap();
public static final String redisVersion = "7.0.15";
public static RedisExecProvider defaultProvider() {
return new RedisExecProvider();
}
private RedisExecProvider() {
initExecutables();
}
private void initExecutables() {
executables.put(OsArchitecture.WINDOWS_x86, "redis-server-2.8.19.exe");
executables.put(OsArchitecture.WINDOWS_x86_64, "redis-server-2.8.19.exe");
executables.put(OsArchitecture.UNIX_x86, "redis-server-" + redisVersion + "-linux-386");
executables.put(OsArchitecture.UNIX_x86_64, "redis-server-" + redisVersion + "-linux-amd64");
executables.put(OsArchitecture.UNIX_arm64, "redis-server-" + redisVersion + "-linux-arm64");
executables.put(OsArchitecture.UNIX_x86, "redis-server-2.8.19-32");
executables.put(OsArchitecture.UNIX_x86_64, "redis-server-2.8.19");
executables.put(OsArchitecture.MAC_OS_X_x86, "redis-server-2.8.19.app");
executables.put(OsArchitecture.MAC_OS_X_x86_64, "redis-server-2.8.19.app");
executables.put(OsArchitecture.MAC_OS_X_x86_64, "redis-server-" + redisVersion + "-darwin-amd64");
executables.put(OsArchitecture.MAC_OS_X_arm64, "redis-server-" + redisVersion + "-darwin-arm64");
}
public RedisExecProvider override(OS os, String executable) {
@ -47,14 +47,20 @@ public class RedisExecProvider {
executables.put(new OsArchitecture(os, arch), executable);
return this;
}
public File get() throws IOException {
OsArchitecture osArch = OsArchitecture.detect();
if (!executables.containsKey(osArch)) {
throw new IllegalArgumentException("No Redis executable found for " + osArch);
}
String executablePath = executables.get(osArch);
return fileExists(executablePath) ?
return fileExists(executablePath) ?
new File(executablePath) :
JarUtil.extractExecutableFromJar(executablePath);
}
private boolean fileExists(String executablePath) {

View File

@ -7,6 +7,7 @@ import redis.embedded.exceptions.RedisBuildingException;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@ -139,7 +140,7 @@ public class RedisSentinelBuilder {
File redisConfigFile = File.createTempFile(resolveConfigName(), ".conf");
redisConfigFile.deleteOnExit();
Files.write(configString, redisConfigFile, Charset.forName("UTF-8"));
Files.asCharSink(redisConfigFile, StandardCharsets.UTF_8).write(configString);
sentinelConf = redisConfigFile.getAbsolutePath();
}

View File

@ -19,6 +19,11 @@ public class RedisServer extends AbstractRedisInstance {
this.args = builder().port(port).build().args;
}
public RedisServer(int port, int tlsPort) {
super(port, tlsPort);
this.args = builder().port(port).tlsPort(tlsPort).build().args;
}
public RedisServer(File executable, int port) {
super(port);
this.args = Arrays.asList(
@ -35,9 +40,9 @@ public class RedisServer extends AbstractRedisInstance {
);
}
RedisServer(List<String> args, int port) {
super(port);
this.args = new ArrayList<String>(args);
RedisServer(List<String> args, int port, int tlsPort) {
super(port, tlsPort);
this.args = new ArrayList<>(args);
}
public static RedisServerBuilder builder() {

View File

@ -8,6 +8,7 @@ import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@ -19,6 +20,7 @@ public class RedisServerBuilder {
private RedisExecProvider redisExecProvider = RedisExecProvider.defaultProvider();
private String bind="127.0.0.1";
private int port = 6379;
private int tlsPort = 0;
private InetSocketAddress slaveOf;
private String redisConf;
@ -39,6 +41,11 @@ public class RedisServerBuilder {
return this;
}
public RedisServerBuilder tlsPort(int tlsPort) {
this.tlsPort = tlsPort;
return this;
}
public RedisServerBuilder slaveOf(String hostname, int port) {
this.slaveOf = new InetSocketAddress(hostname, port);
return this;
@ -75,7 +82,7 @@ public class RedisServerBuilder {
setting("bind "+bind);
tryResolveConfAndExec();
List<String> args = buildCommandArgs();
return new RedisServer(args, port);
return new RedisServer(args, port, tlsPort);
}
public void reset() {
@ -97,7 +104,7 @@ public class RedisServerBuilder {
if (redisConf == null && redisConfigBuilder != null) {
File redisConfigFile = File.createTempFile(resolveConfigName(), ".conf");
redisConfigFile.deleteOnExit();
Files.write(redisConfigBuilder.toString(), redisConfigFile, Charset.forName("UTF-8"));
Files.asCharSink(redisConfigFile, StandardCharsets.UTF_8).write(redisConfigBuilder.toString());
redisConf = redisConfigFile.getAbsolutePath();
}
@ -123,6 +130,11 @@ public class RedisServerBuilder {
args.add("--port");
args.add(Integer.toString(port));
if (tlsPort > 0) {
args.add("--tls-port");
args.add(Integer.toString(tlsPort));
}
if (slaveOf != null) {
args.add("--slaveof");
args.add(slaveOf.getHostName());

View File

@ -2,5 +2,6 @@ package redis.embedded.util;
public enum Architecture {
x86,
x86_64
x86_64,
arm64
}

View File

@ -10,14 +10,20 @@ import java.io.IOException;
public class JarUtil {
public static File extractExecutableFromJar(String executable) throws IOException {
File tmpDir = Files.createTempDir();
tmpDir.deleteOnExit();
File command = new File(tmpDir, executable);
FileUtils.copyURLToFile(Resources.getResource(executable), command);
command.deleteOnExit();
File command = extractFileFromJar(executable);
command.setExecutable(true);
return command;
}
public static File extractFileFromJar(String path) throws IOException {
File tmpDir = Files.createTempDir();
tmpDir.deleteOnExit();
File file = new File(tmpDir, path);
FileUtils.copyURLToFile(Resources.getResource(path), file);
file.deleteOnExit();
return file;
}
}

View File

@ -47,58 +47,46 @@ public class OSDetector {
}
private static Architecture getUnixArchitecture() {
BufferedReader input = null;
try {
String line;
Process proc = Runtime.getRuntime().exec("uname -m");
input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while ((line = input.readLine()) != null) {
if (line.length() > 0) {
if (line.contains("64")) {
try (BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String machine = input.readLine();
switch (machine) {
case "aarch64":
return Architecture.arm64;
case "x86_64":
return Architecture.x86_64;
}
default:
throw new OsDetectionException("unsupported architecture: " + machine);
}
}
} catch (Exception e) {
throw new OsDetectionException(e);
} finally {
try {
if (input != null) {
input.close();
}
} catch (Exception ignored) {
// ignore
if (e instanceof OsDetectionException) {
throw (OsDetectionException)e;
}
throw new OsDetectionException(e);
}
return Architecture.x86;
}
private static Architecture getMacOSXArchitecture() {
BufferedReader input = null;
try {
String line;
Process proc = Runtime.getRuntime().exec("sysctl hw");
input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while ((line = input.readLine()) != null) {
if (line.length() > 0) {
if ((line.contains("cpu64bit_capable")) && (line.trim().endsWith("1"))) {
Process proc = Runtime.getRuntime().exec("uname -m");
try (BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String machine = input.readLine();
switch (machine) {
case "arm64":
return Architecture.arm64;
case "x86_64":
return Architecture.x86_64;
}
default:
throw new OsDetectionException("unsupported architecture: " + machine);
}
}
} catch (Exception e) {
throw new OsDetectionException(e);
} finally {
try {
if (input != null) {
input.close();
}
} catch (Exception ignored) {
// ignore
if (e instanceof OsDetectionException) {
throw (OsDetectionException)e;
}
throw new OsDetectionException(e);
}
return Architecture.x86;
}
}

View File

@ -4,14 +4,12 @@ import com.google.common.base.Preconditions;
public class OsArchitecture {
public static final OsArchitecture WINDOWS_x86 = new OsArchitecture(OS.WINDOWS, Architecture.x86);
public static final OsArchitecture WINDOWS_x86_64 = new OsArchitecture(OS.WINDOWS, Architecture.x86_64);
public static final OsArchitecture UNIX_x86 = new OsArchitecture(OS.UNIX, Architecture.x86);
public static final OsArchitecture UNIX_x86_64 = new OsArchitecture(OS.UNIX, Architecture.x86_64);
public static final OsArchitecture UNIX_arm64 = new OsArchitecture(OS.UNIX, Architecture.arm64);
public static final OsArchitecture MAC_OS_X_x86 = new OsArchitecture(OS.MAC_OS_X, Architecture.x86);
public static final OsArchitecture MAC_OS_X_x86_64 = new OsArchitecture(OS.MAC_OS_X, Architecture.x86_64);
public static final OsArchitecture MAC_OS_X_arm64 = new OsArchitecture(OS.MAC_OS_X, Architecture.arm64);
private final OS os;
private final Architecture arch;
@ -55,4 +53,9 @@ public class OsArchitecture {
result = 31 * result + arch.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s (%s)", os.name(), arch.name());
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
#!/bin/bash
rm -rf ./tests

View File

@ -0,0 +1,7 @@
#!/bin/bash
OUTPUT_DIR="$1"
if [ ! -f "$OUTPUT_DIR/redis.key" -o ! -f "$OUTPUT_DIR/redis.crt" -o ! -f "$OUTPUT_DIR/ca.crt" ]; then
./gen-test-certs.sh
fi

73
src/test/bash/gen-test-certs.sh Executable file
View File

@ -0,0 +1,73 @@
#!/bin/bash
# From https://github.com/redis/redis/blob/4930d19e70c391750479951022e207e19111eb55/redis/util/gen-test-certs.sh, under the license:
#
# Copyright (c) 2006-2020, Salvatore Sanfilippo
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
# * Neither the name of Redis nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Generate some test certificates which are used by the regression test suite:
#
# tests/tls/ca.{crt,key} Self signed CA certificate.
# tests/tls/redis.{crt,key} A certificate with no key usage/policy restrictions.
# tests/tls/client.{crt,key} A certificate restricted for SSL client usage.
# tests/tls/server.{crt,key} A certificate restricted fro SSL server usage.
# tests/tls/redis.dh DH Params file.
generate_cert() {
local name=$1
local cn="$2"
local opts="$3"
local keyfile=tests/tls/${name}.key
local certfile=tests/tls/${name}.crt
[ -f $keyfile ] || openssl genrsa -out $keyfile 2048
openssl req \
-new -sha256 \
-subj "/O=Redis Test/CN=$cn" \
-key $keyfile | \
openssl x509 \
-req -sha256 \
-CA tests/tls/ca.crt \
-CAkey tests/tls/ca.key \
-CAserial tests/tls/ca.txt \
-CAcreateserial \
-days 365 \
$opts \
-out $certfile
}
mkdir -p tests/tls
[ -f tests/tls/ca.key ] || openssl genrsa -out tests/tls/ca.key 4096
openssl req \
-x509 -new -nodes -sha256 \
-key tests/tls/ca.key \
-days 3650 \
-subj '/O=Redis Test/CN=Certificate Authority' \
-out tests/tls/ca.crt
cat > tests/tls/openssl.cnf <<_END_
[ server_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = server
[ client_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = client
_END_
generate_cert server "Server-only" "-extfile tests/tls/openssl.cnf -extensions server_cert"
generate_cert client "Client-only" "-extfile tests/tls/openssl.cnf -extensions client_cert"
generate_cert redis "Generic-cert"
[ -f tests/tls/redis.dh ] || openssl dhparam -out tests/tls/redis.dh 2048

View File

@ -1,12 +1,15 @@
package redis.embedded;
import com.google.common.collect.Sets;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.embedded.util.JedisUtil;
import java.io.Closeable;
import java.net.Inet4Address;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@ -17,6 +20,9 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class RedisClusterTest {
private final RedisSentinelBuilder sentinelBuilder = RedisSentinel.builder();
private String bindAddress;
private Redis sentinel1;
private Redis sentinel2;
private Redis master1;
@ -30,6 +36,13 @@ public class RedisClusterTest {
sentinel2 = mock(Redis.class);
master1 = mock(Redis.class);
master2 = mock(Redis.class);
// Jedis translates localhost to getLocalHost().getHostAddress() (see Jedis HostAndPort#getLocalHostQuietly),
// which can vary from 127.0.0.1 (most notably, Debian/Ubuntu return 127.0.1.1)
if (bindAddress == null) {
bindAddress = Inet4Address.getLocalHost().getHostAddress();
sentinelBuilder.bind(bindAddress);
}
}
@ -97,7 +110,7 @@ public class RedisClusterTest {
@Test
public void testSimpleOperationsAfterRunWithSingleMasterNoSlavesCluster() throws Exception {
//given
final RedisCluster cluster = RedisCluster.builder().sentinelCount(1).replicationGroup("ourmaster", 0).build();
final RedisCluster cluster = RedisCluster.builder().withSentinelBuilder(sentinelBuilder).sentinelCount(1).replicationGroup("ourmaster", 0).build();
cluster.start();
//when
@ -107,8 +120,7 @@ public class RedisClusterTest {
pool = new JedisSentinelPool("ourmaster", Sets.newHashSet("localhost:26379"));
jedis = testPool(pool);
} finally {
if (jedis != null)
pool.returnResource(jedis);
closeQuietly(jedis, pool);
cluster.stop();
}
}
@ -116,7 +128,7 @@ public class RedisClusterTest {
@Test
public void testSimpleOperationsAfterRunWithSingleMasterAndOneSlave() throws Exception {
//given
final RedisCluster cluster = RedisCluster.builder().sentinelCount(1).replicationGroup("ourmaster", 1).build();
final RedisCluster cluster = RedisCluster.builder().withSentinelBuilder(sentinelBuilder).sentinelCount(1).replicationGroup("ourmaster", 1).build();
cluster.start();
//when
@ -126,8 +138,7 @@ public class RedisClusterTest {
pool = new JedisSentinelPool("ourmaster", Sets.newHashSet("localhost:26379"));
jedis = testPool(pool);
} finally {
if (jedis != null)
pool.returnResource(jedis);
closeQuietly(jedis, pool);
cluster.stop();
}
}
@ -135,7 +146,7 @@ public class RedisClusterTest {
@Test
public void testSimpleOperationsAfterRunWithSingleMasterMultipleSlaves() throws Exception {
//given
final RedisCluster cluster = RedisCluster.builder().sentinelCount(1).replicationGroup("ourmaster", 2).build();
final RedisCluster cluster = RedisCluster.builder().withSentinelBuilder(sentinelBuilder).sentinelCount(1).replicationGroup("ourmaster", 2).build();
cluster.start();
//when
@ -145,8 +156,7 @@ public class RedisClusterTest {
pool = new JedisSentinelPool("ourmaster", Sets.newHashSet("localhost:26379"));
jedis = testPool(pool);
} finally {
if (jedis != null)
pool.returnResource(jedis);
closeQuietly(jedis, pool);
cluster.stop();
}
}
@ -154,7 +164,7 @@ public class RedisClusterTest {
@Test
public void testSimpleOperationsAfterRunWithTwoSentinelsSingleMasterMultipleSlaves() throws Exception {
//given
final RedisCluster cluster = RedisCluster.builder().sentinelCount(2).replicationGroup("ourmaster", 2).build();
final RedisCluster cluster = RedisCluster.builder().withSentinelBuilder(sentinelBuilder).sentinelCount(2).replicationGroup("ourmaster", 2).build();
cluster.start();
//when
@ -164,8 +174,7 @@ public class RedisClusterTest {
pool = new JedisSentinelPool("ourmaster", Sets.newHashSet("localhost:26379", "localhost:26380"));
jedis = testPool(pool);
} finally {
if (jedis != null)
pool.returnResource(jedis);
closeQuietly(jedis, pool);
cluster.stop();
}
}
@ -174,7 +183,7 @@ public class RedisClusterTest {
public void testSimpleOperationsAfterRunWithTwoPredefinedSentinelsSingleMasterMultipleSlaves() throws Exception {
//given
List<Integer> sentinelPorts = Arrays.asList(26381, 26382);
final RedisCluster cluster = RedisCluster.builder().sentinelPorts(sentinelPorts).replicationGroup("ourmaster", 2).build();
final RedisCluster cluster = RedisCluster.builder().withSentinelBuilder(sentinelBuilder).sentinelPorts(sentinelPorts).replicationGroup("ourmaster", 2).build();
cluster.start();
final Set<String> sentinelHosts = JedisUtil.portsToJedisHosts(sentinelPorts);
@ -185,8 +194,7 @@ public class RedisClusterTest {
pool = new JedisSentinelPool("ourmaster", sentinelHosts);
jedis = testPool(pool);
} finally {
if (jedis != null)
pool.returnResource(jedis);
closeQuietly(jedis, pool);
cluster.stop();
}
}
@ -197,7 +205,7 @@ public class RedisClusterTest {
final String master1 = "master1";
final String master2 = "master2";
final String master3 = "master3";
final RedisCluster cluster = RedisCluster.builder().sentinelCount(3).quorumSize(2)
final RedisCluster cluster = RedisCluster.builder().withSentinelBuilder(sentinelBuilder).sentinelCount(3).quorumSize(2)
.replicationGroup(master1, 1)
.replicationGroup(master2, 1)
.replicationGroup(master3, 1)
@ -219,12 +227,7 @@ public class RedisClusterTest {
jedis2 = testPool(pool2);
jedis3 = testPool(pool3);
} finally {
if (jedis1 != null)
pool1.returnResource(jedis1);
if (jedis2 != null)
pool2.returnResource(jedis2);
if (jedis3 != null)
pool3.returnResource(jedis3);
closeQuietly(jedis1, pool1, jedis2, pool2, jedis3, pool3);
cluster.stop();
}
}
@ -235,7 +238,7 @@ public class RedisClusterTest {
final String master1 = "master1";
final String master2 = "master2";
final String master3 = "master3";
final RedisCluster cluster = RedisCluster.builder().ephemeral().sentinelCount(3).quorumSize(2)
final RedisCluster cluster = RedisCluster.builder().withSentinelBuilder(sentinelBuilder).ephemeral().sentinelCount(3).quorumSize(2)
.replicationGroup(master1, 1)
.replicationGroup(master2, 1)
.replicationGroup(master3, 1)
@ -258,12 +261,7 @@ public class RedisClusterTest {
jedis2 = testPool(pool2);
jedis3 = testPool(pool3);
} finally {
if (jedis1 != null)
pool1.returnResource(jedis1);
if (jedis2 != null)
pool2.returnResource(jedis2);
if (jedis3 != null)
pool3.returnResource(jedis3);
closeQuietly(jedis1, pool1, jedis2, pool2, jedis3, pool3);
cluster.stop();
}
}
@ -279,4 +277,11 @@ public class RedisClusterTest {
assertEquals(null, jedis.mget("xyz").get(0));
return jedis;
}
}
private void closeQuietly(Closeable... closeables) {
for (Closeable closeable : closeables) {
IOUtils.closeQuietly(closeable, null);
}
}
}

View File

@ -1,6 +1,7 @@
package redis.embedded;
import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
@ -8,18 +9,30 @@ import redis.clients.jedis.JedisSentinelPool;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.*;
public class RedisSentinelTest {
private String bindAddress;
private RedisSentinel sentinel;
private RedisServer server;
@Before
public void setup() throws Exception {
// Jedis translates localhost to getLocalHost().getHostAddress() (see Jedis HostAndPort#getLocalHostQuietly),
// which can vary from 127.0.0.1 (most notably, Debian/Ubuntu return 127.0.1.1)
if (bindAddress == null) {
bindAddress = Inet4Address.getLocalHost().getHostAddress();
}
}
@Test(timeout = 3000L)
public void testSimpleRun() throws Exception {
server = new RedisServer();
sentinel = RedisSentinel.builder().build();
sentinel = RedisSentinel.builder().bind(bindAddress).build();
sentinel.start();
server.start();
TimeUnit.SECONDS.sleep(1);
@ -29,7 +42,7 @@ public class RedisSentinelTest {
@Test
public void shouldAllowSubsequentRuns() throws Exception {
sentinel = RedisSentinel.builder().build();
sentinel = RedisSentinel.builder().bind(bindAddress).build();
sentinel.start();
sentinel.stop();
@ -44,7 +57,7 @@ public class RedisSentinelTest {
public void testSimpleOperationsAfterRun() throws Exception {
//given
server = new RedisServer();
sentinel = RedisSentinel.builder().build();
sentinel = RedisSentinel.builder().bind(bindAddress).build();
server.start();
sentinel.start();
TimeUnit.SECONDS.sleep(1);
@ -99,4 +112,4 @@ public class RedisSentinelTest {
assertNotNull(outputLine);
} while (!outputLine.matches(readyPattern));
}
}
}

View File

@ -97,11 +97,11 @@ public class RedisServerTest {
@Test
public void shouldOverrideDefaultExecutable() throws Exception {
RedisExecProvider customProvider = RedisExecProvider.defaultProvider()
.override(OS.UNIX, Architecture.x86, Resources.getResource("redis-server-2.8.19-32").getFile())
.override(OS.UNIX, Architecture.x86_64, Resources.getResource("redis-server-2.8.19").getFile())
.override(OS.WINDOWS, Architecture.x86, Resources.getResource("redis-server-2.8.19.exe").getFile())
.override(OS.WINDOWS, Architecture.x86_64, Resources.getResource("redis-server-2.8.19.exe").getFile())
.override(OS.MAC_OS_X, Resources.getResource("redis-server-2.8.19").getFile());
.override(OS.UNIX, Architecture.x86, Resources.getResource("redis-server-" + RedisExecProvider.redisVersion + "-linux-386").getFile())
.override(OS.UNIX, Architecture.x86_64, Resources.getResource("redis-server-" + RedisExecProvider.redisVersion + "-linux-amd64").getFile())
.override(OS.UNIX, Architecture.arm64, Resources.getResource("redis-server-" + RedisExecProvider.redisVersion + "-linux-arm64").getFile())
.override(OS.MAC_OS_X, Architecture.x86_64, Resources.getResource("redis-server-" + RedisExecProvider.redisVersion + "-darwin-amd64").getFile())
.override(OS.MAC_OS_X, Architecture.arm64, Resources.getResource("redis-server-" + RedisExecProvider.redisVersion + "-darwin-arm64").getFile());
redisServer = new RedisServerBuilder()
.redisExecProvider(customProvider)
@ -112,8 +112,6 @@ public class RedisServerTest {
public void shouldFailWhenBadExecutableGiven() throws Exception {
RedisExecProvider buggyProvider = RedisExecProvider.defaultProvider()
.override(OS.UNIX, "some")
.override(OS.WINDOWS, Architecture.x86, "some")
.override(OS.WINDOWS, Architecture.x86_64, "some")
.override(OS.MAC_OS_X, "some");
redisServer = new RedisServerBuilder()
@ -142,6 +140,12 @@ public class RedisServerTest {
.getClassLoader()
.getResourceAsStream("redis-4.x-standalone-startup-output.txt"))),
readyPattern);
assertReadyPattern(new BufferedReader(
new InputStreamReader(getClass()
.getClassLoader()
.getResourceAsStream("redis-6.x-standalone-startup-output.txt"))),
readyPattern);
}
private void assertReadyPattern(BufferedReader reader, String readyPattern) throws IOException {

View File

@ -0,0 +1,101 @@
package redis.embedded;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.embedded.util.JarUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class RedisTlsTest {
private RedisServer redisServer;
private static File certFile;
private static File keyFile;
private static File caCertFile;
@BeforeClass
public static void setupClass() throws Exception {
certFile = getFile("redis.crt");
keyFile = getFile("redis.key");
caCertFile = getFile("ca.crt");
File trustStore = File.createTempFile("embedded-redis-test-truststore", ".jks");
trustStore.deleteOnExit();
Certificate cert;
try (FileInputStream certInput = new FileInputStream(certFile)) {
cert = CertificateFactory.getInstance("X.509").generateCertificate(certInput);
}
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(null, null);
keyStore.setCertificateEntry("testCaCert", cert);
try (FileOutputStream out = new FileOutputStream(trustStore)) {
keyStore.store(out, new char[0]);
}
System.setProperty("javax.net.ssl.trustStore", trustStore.getAbsolutePath());
System.setProperty("javax.net.ssl.trustStoreType", "jks");
}
@Before
public void setup() throws Exception {
redisServer = RedisServer.builder()
.port(0) // disable non-tls
.tlsPort(6380)
.setting("tls-cert-file " + certFile.getAbsolutePath())
.setting("tls-key-file " + keyFile.getAbsolutePath())
.setting("tls-ca-cert-file " + caCertFile.getAbsolutePath())
.setting("tls-auth-clients no") // disable mTLS, for simplicity
.build();
}
@Test(timeout = 1500L)
public void testSimpleRun() throws Exception {
redisServer.start();
Thread.sleep(1000L);
redisServer.stop();
}
@Test
public void testSimpleOperationsAfterRun() {
redisServer.start();
try (JedisPool pool = new JedisPool("localhost", redisServer.tlsPorts().get(0), true);
Jedis jedis = pool.getResource()) {
jedis.mset("abc", "1", "def", "2");
assertEquals("1", jedis.mget("abc").get(0));
assertEquals("2", jedis.mget("def").get(0));
assertNull(jedis.mget("xyz").get(0));
} finally {
redisServer.stop();
}
}
private static File getFile(String path) throws IOException {
return fileExists(path) ?
new File(path) :
JarUtil.extractFileFromJar(path);
}
private static boolean fileExists(String path) {
return new File(path).exists();
}
}

View File

@ -1,49 +0,0 @@
package redis.embedded;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisShardInfo;
import static org.junit.Assert.assertEquals;
public class SpringDataConnectivityTest {
private RedisServer redisServer;
private RedisTemplate<String, String> template;
private JedisConnectionFactory connectionFactory;
@Before
public void setUp() throws Exception {
redisServer = new RedisServer(6379);
redisServer.start();
JedisShardInfo shardInfo = new JedisShardInfo("localhost", 6379);
connectionFactory = new JedisConnectionFactory();
connectionFactory.setShardInfo(shardInfo);
template = new StringRedisTemplate();
template.setConnectionFactory(connectionFactory);
template.afterPropertiesSet();
}
@Test
public void shouldBeAbleToUseSpringData() throws Exception {
// given
template.opsForValue().set("foo", "bar");
// when
String result = template.opsForValue().get("foo");
// then
assertEquals("bar", result);
}
@After
public void tearDown() throws Exception {
redisServer.stop();
}
}

View File

@ -0,0 +1,26 @@
124304:C 26 Jun 2020 12:23:30.115 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
124304:C 26 Jun 2020 12:23:30.115 # Redis version=6.0.5, bits=64, commit=00000000, modified=0, pid=124304, just started
124304:C 26 Jun 2020 12:23:30.115 # Warning: no config file specified, using the default config. In order to specify a config file use ./src/main/resources/redis-server-6.0.5 /path/to/redis.conf
124304:M 26 Jun 2020 12:23:30.116 * Increased maximum number of open files to 10032 (it was originally set to 1024).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.0.5 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 124304
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
124304:M 26 Jun 2020 12:23:30.116 # Server initialized
124304:M 26 Jun 2020 12:23:30.116 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
124304:M 26 Jun 2020 12:23:30.116 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
124304:M 26 Jun 2020 12:23:30.116 * Ready to accept connections