downloadPlatformName = new HashMap<>(3);
59 | static {
60 | downloadPlatformName.put(OperatingSystem.MAC_OS, "mac-standalone");
61 | downloadPlatformName.put(OperatingSystem.UNIX, "generic-unix");
62 | downloadPlatformName.put(OperatingSystem.WINDOWS, "windows");
63 | }
64 |
65 | private final String urlPattern;
66 |
67 | OfficialArtifactRepository(String urlPattern) {
68 | this.urlPattern = urlPattern;
69 | }
70 |
71 | @Override
72 | public URL getUrl(Version version, OperatingSystem operatingSystem) {
73 | String artifactPlatform = getArtifactPlatform(version, operatingSystem);
74 | ArchiveType archiveType = version.getArchiveType(operatingSystem);
75 |
76 | String filenameVersion = version.getVersionAsString();
77 | String folderPrefix = getFolderPrefix(version);
78 | String folderVersion = getFolderVersion(version);
79 |
80 | String url = String.format(urlPattern,
81 | folderPrefix, folderVersion, artifactPlatform, filenameVersion, archiveType.getExtension());
82 | try {
83 | return new URL(url);
84 | } catch (MalformedURLException e) {
85 | throw new IllegalStateException("Download URL is invalid: " + url, e);
86 | }
87 | }
88 |
89 | /**
90 | * RabbitMQ releases used to include a special binary package for macOS that bundled a supported version of
91 | * Erlang/OTP. As of September 2019, this package has been discontinued.
92 | * It will no longer be produced for new RabbitMQ releases.
93 | *
94 | * MacOS users should use the Homebrew formula or the generic binary build (requires a supported version of Erlang
95 | * to be installed separately) to provision RabbitMQ.
96 | *
97 | * @see Announcement
98 | */
99 | protected String getArtifactPlatform(Version version, OperatingSystem operatingSystem) {
100 | if (operatingSystem == OperatingSystem.MAC_OS
101 | && Version.VERSION_COMPARATOR.compare(PredefinedVersion.V3_7_18, version) <= 0) {
102 | // v3.7.18 was the first Sep. 2019 release
103 | return downloadPlatformName.get(OperatingSystem.UNIX);
104 | }
105 | return downloadPlatformName.get(operatingSystem);
106 | }
107 |
108 | protected String getFolderVersion(Version version) {
109 | return version.getVersionAsString();
110 | }
111 |
112 | protected String getFolderPrefix(Version version) {
113 | return "";
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/PredefinedVersion.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.util.ArchiveType;
4 | import io.arivera.oss.embedded.rabbitmq.util.OperatingSystem;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * A list of RabbitMQ versions pre-configured to match the binaries distributed officially by RabbitMQ.
10 | *
11 | * Use this enum while building the {@link EmbeddedRabbitMqConfig} instance to specify a version to
12 | * {@link EmbeddedRabbitMq#start() start}
13 | *
14 | * @see io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig.Builder#version(Version)
15 | */
16 | public enum PredefinedVersion implements Version {
17 |
18 | V3_8_14(new BaseVersion("3.8.14", ErlangVersion.V22_3)),
19 | V3_8_13(new BaseVersion("3.8.13", ErlangVersion.V22_3)),
20 | V3_8_12(new BaseVersion("3.8.12", ErlangVersion.V22_3)),
21 | V3_8_11(new BaseVersion("3.8.11", ErlangVersion.V22_3)),
22 | V3_8_10(new BaseVersion("3.8.10", ErlangVersion.V22_3)),
23 | V3_8_9( new BaseVersion("3.8.9", ErlangVersion.V22_3)),
24 |
25 | V3_8_8(new BaseVersion("3.8.8", ErlangVersion.V21_3)),
26 | V3_8_7(new BaseVersion("3.8.7", ErlangVersion.V21_3)),
27 | V3_8_6(new BaseVersion("3.8.6", ErlangVersion.V21_3)),
28 | V3_8_5(new BaseVersion("3.8.5", ErlangVersion.V21_3)),
29 | V3_8_4(new BaseVersion("3.8.4", ErlangVersion.V21_3)),
30 |
31 |
32 | V3_8_3(new BaseVersion("3.8.3", ErlangVersion.V21_3)),
33 | V3_8_2(new BaseVersion("3.8.2", ErlangVersion.V21_3)),
34 | V3_8_1(new BaseVersion("3.8.1", ErlangVersion.V21_3)),
35 | V3_8_0(new BaseVersion("3.8.0", ErlangVersion.V21_3)),
36 |
37 | V3_7_18(new BaseVersion("3.7.18", ErlangVersion.V20_3)),
38 | V3_7_7(new BaseVersion("3.7.7", ErlangVersion.V19_3_6_4)),
39 | V3_7_6(new BaseVersion("3.7.6", ErlangVersion.V19_3)),
40 | V3_7_5(new BaseVersion("3.7.5", ErlangVersion.V19_3)),
41 | V3_7_4(new BaseVersion("3.7.4", ErlangVersion.V19_3)),
42 | V3_7_3(new BaseVersion("3.7.3", ErlangVersion.V19_3)),
43 | V3_7_2(new BaseVersion("3.7.2", ErlangVersion.V19_3)),
44 | V3_7_1(new BaseVersion("3.7.1", ErlangVersion.V19_3)),
45 | V3_7_0(new BaseVersion("3.7.0", ErlangVersion.V19_3)),
46 |
47 | V3_6_16(new BaseVersion("3.6.16", ErlangVersion.V19_3)),
48 | V3_6_15(new BaseVersion("3.6.15", ErlangVersion.V19_3)),
49 | V3_6_14(new BaseVersion("3.6.14", ErlangVersion.R16B03)),
50 | V3_6_13(new BaseVersion("3.6.13", ErlangVersion.R16B03)),
51 | V3_6_12(new BaseVersion("3.6.12", ErlangVersion.R16B03)),
52 | V3_6_11(new BaseVersion("3.6.11", ErlangVersion.R16B03)),
53 | V3_6_10(new BaseVersion("3.6.10", ErlangVersion.R16B03)),
54 | V3_6_9(new BaseVersion("3.6.9", ErlangVersion.R16B03)),
55 | V3_6_8(new BaseVersion("3.6.8", ErlangVersion.R16B03)),
56 | V3_6_7(new BaseVersion("3.6.7", ErlangVersion.R16B03)),
57 | V3_6_6(new BaseVersion("3.6.6", ErlangVersion.R16B03)),
58 | V3_6_5(new BaseVersion("3.6.5", ErlangVersion.R16B03)),
59 | V3_6_4(new BaseVersion("3.6.4", ErlangVersion.R16B03)),
60 | V3_6_3(new BaseVersion("3.6.3", ErlangVersion.R16B03)),
61 | V3_6_2(new BaseVersion("3.6.2", ErlangVersion.R16B03)),
62 | V3_6_1(new BaseVersion("3.6.1", ErlangVersion.R16B03)),
63 | V3_6_0(new BaseVersion("3.6.0", ErlangVersion.R16B03)),
64 |
65 | V3_5_7(new BaseVersion("3.5.7", ErlangVersion.R13B03, ArchiveType.TAR_GZ)),
66 | V3_5_6(new BaseVersion("3.5.6", ErlangVersion.R13B03, ArchiveType.TAR_GZ)),
67 | V3_5_5(new BaseVersion("3.5.5", ErlangVersion.R13B03, ArchiveType.TAR_GZ)),
68 | V3_5_4(new BaseVersion("3.5.4", ErlangVersion.R13B03, ArchiveType.TAR_GZ)),
69 | V3_5_3(new BaseVersion("3.5.3", ErlangVersion.R13B03, ArchiveType.TAR_GZ)),
70 | V3_5_2(new BaseVersion("3.5.2", ErlangVersion.R13B03, ArchiveType.TAR_GZ)),
71 | V3_5_1(new BaseVersion("3.5.1", ErlangVersion.R13B03, ArchiveType.TAR_GZ)),
72 | V3_5_0(new BaseVersion("3.5.0", ErlangVersion.R13B03, ArchiveType.TAR_GZ)),
73 |
74 | V3_4_4(new BaseVersion("3.4.4", ErlangVersion.UNKNOWN, ArchiveType.TAR_GZ)),
75 | V3_4_3(new BaseVersion("3.4.3", ErlangVersion.UNKNOWN, ArchiveType.TAR_GZ)),
76 | V3_4_2(new BaseVersion("3.4.2", ErlangVersion.UNKNOWN, ArchiveType.TAR_GZ)),
77 | V3_4_1(new BaseVersion("3.4.1", ErlangVersion.UNKNOWN, ArchiveType.TAR_GZ)),
78 | V3_4_0(new BaseVersion("3.4.0", ErlangVersion.UNKNOWN, ArchiveType.TAR_GZ)),
79 |
80 | LATEST(V3_8_14);
81 |
82 | final Version version;
83 |
84 | PredefinedVersion(Version version) {
85 | this.version = version;
86 | }
87 |
88 | @Override
89 | public List getVersionComponents() {
90 | return version.getVersionComponents();
91 | }
92 |
93 | @Override
94 | public String getVersionAsString() {
95 | return version.getVersionAsString();
96 | }
97 |
98 | @Override
99 | public String getVersionAsString(CharSequence separator) {
100 | return version.getVersionAsString(separator);
101 | }
102 |
103 | @Override
104 | public ArchiveType getArchiveType(OperatingSystem operatingSystem) {
105 | return version.getArchiveType(operatingSystem);
106 | }
107 |
108 | @Override
109 | public String getExtractionFolder() {
110 | return version.getExtractionFolder();
111 | }
112 |
113 | @Override
114 | public String getMinimumErlangVersion() {
115 | return version.getMinimumErlangVersion();
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/RabbitMqEnvVar.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq;
2 |
3 | /**
4 | * A list of RabbitMQ environment variables used to configure the broker's behavior.
5 | *
6 | * @see https://www.rabbitmq.com/configure.html
7 | */
8 | public enum RabbitMqEnvVar {
9 |
10 | /**
11 | * Use this if you only want to bind to one network interface. To bind to two or more interfaces, use the
12 | * {@code tcp_listeners} key in {@code rabbitmq.config}.
13 | *
14 | * Default value: empty string - meaning bind to all network interfaces
15 | */
16 | NODE_IP_ADDRESS,
17 |
18 | /**
19 | * The port to bind this RabbitMQ broker node.
20 | *
21 | * Default value: {@value DEFAULT_NODE_PORT}
22 | */
23 | NODE_PORT,
24 |
25 | /**
26 | * Port to use for clustering. Ignored if your config file sets {@code inet_dist_listen_min} or
27 | * {@code inet_dist_listen_max}
28 | */
29 | DIST_PORT,
30 |
31 | /**
32 | * The node name should be unique per erlang-node-and-machine combination.
33 | *
34 | * To run multiple nodes, see the clustering guide.
35 | *
36 | * Default:
37 | *
38 | * - Unix: {@code rabbit@$HOSTNAME}
39 | * - Windows: {@code rabbit@%COMPUTERNAME%}
40 | *
41 | */
42 | NODENAME,
43 |
44 | /**
45 | * Location of the file that contains environment variable definitions (without the {@code RABBITMQ_} prefix).
46 | *
47 | * Note that the file name on Windows is different from other operating systems.
48 | *
49 | * Defaults:
50 | * Generic UNIX - {@code $RABBITMQ_HOME/etc/rabbitmq/rabbitmq-env.conf}
51 | * Debian - {@code /etc/rabbitmq/rabbitmq-env.conf}
52 | * RPM - {@code /etc/rabbitmq/rabbitmq-env.conf}
53 | * Mac OS X (Homebrew) - {@code $\{install_prefix\}/etc/rabbitmq/rabbitmq-env.conf},
54 | * the Homebrew prefix is usually /usr/local
55 | * Windows - {@code %APPDATA%\RabbitMQ\rabbitmq-env-conf.bat}
56 | *
57 | */
58 | CONF_ENV_FILE,
59 |
60 | /**
61 | * When set to {@code true} this will cause RabbitMQ to use fully qualified names to identify nodes.
62 | *
63 | * This may prove useful on EC2. Note that it is not possible to switch between using short and long names
64 | * without resetting the node.
65 | */
66 | USE_LONGNAME,
67 |
68 | /**
69 | * The name of the installed service. This will appear in services.msc.
70 | *
71 | * Default for Windows: {@code RabbitMQ}
72 | */
73 | SERVICENAME,
74 |
75 | /**
76 | * Set this variable to new or reuse to redirect console output from the server to a file named
77 | * @{code %RABBITMQ_SERVICENAME%.debug} in the default {@code RABBITMQ_BASE} directory.
78 | *
79 | * If not set, console output from the server will be discarded (default).
80 | * {@code new} - A new file will be created each time the service starts.
81 | * {@code reuse} - The file will be overwritten each time the service starts.
82 | *
83 | */
84 | CONSOLE_LOG,
85 |
86 | /**
87 | * Parameters for the erl command used when invoking rabbitmqctl.
88 | *
89 | * This should be overridden for debugging purposes only.
90 | *
91 | * Default: None
92 | */
93 | CTL_ERL_ARGS,
94 |
95 | /**
96 | * Standard parameters for the erl command used when invoking the RabbitMQ Server.
97 | *
98 | * This should be overridden for debugging purposes only. Overriding this variable replaces the default value.
99 | *
100 | * Defaults:
101 | * Unix*: {@code "+K true +A30 +P 1048576 -kernel inet_default_connect_options [{nodelay,true}]"}
102 | * Windows: None
103 | */
104 | SERVER_ERL_ARGS,
105 |
106 | /**
107 | * Additional parameters for the erl command used when invoking the RabbitMQ Server.
108 | *
109 | * The value of this variable is appended the default list of arguments ({@code RABBITMQ_SERVER_ERL_ARGS}).
110 | *
111 | * Defaults:
112 | * - Unix*: None
113 | * - Windows: None
114 | *
115 | */
116 | SERVER_ADDITIONAL_ERL_ARGS,
117 |
118 | /**
119 | * Extra parameters for the erl command used when invoking the RabbitMQ Server.
120 | *
121 | * This will not override {@code RABBITMQ_SERVER_ERL_ARGS}.
122 | *
123 | * Default: None
124 | */
125 | SERVER_START_ARGS,
126 |
127 | /**
128 | * Defines the location of the RabbitMQ core configuration file.
129 | *
130 | * The value should not contain the suffix {@code .config} since Erlang will append it automatically.
131 | */
132 | CONFIG_FILE;
133 |
134 | public static final int DEFAULT_NODE_PORT = 5672;
135 |
136 | private static final String ENV_VAR_PREFIX = "RABBITMQ_";
137 |
138 | RabbitMqEnvVar() {
139 | }
140 |
141 | /**
142 | * @return environment variable name (with the prefix {@code RABBITMQ_}).
143 | */
144 | public String getEnvVarName() {
145 | return ENV_VAR_PREFIX + name();
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/SingleArtifactRepository.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.util.OperatingSystem;
4 |
5 | import java.net.URL;
6 |
7 | /**
8 | * Class used to allow for the user to specify a custom URL to download the RabbitMQ binary from.
9 | *
10 | * Since this is basically a hardcoded URL, there's no ability to change the artifact to be downloaded based on
11 | * the OS the system is currently running. Use a {@link BaseVersion} if that capability is needed.
12 | *
13 | * @see EmbeddedRabbitMqConfig.Builder#downloadFrom(ArtifactRepository)
14 | * @see EmbeddedRabbitMqConfig.Builder#downloadFrom(URL, String)
15 | */
16 | class SingleArtifactRepository implements ArtifactRepository {
17 |
18 | private final URL downloadSource;
19 |
20 | SingleArtifactRepository(URL downloadSource) {
21 | this.downloadSource = downloadSource;
22 | }
23 |
24 | @Override
25 | public URL getUrl(Version version, OperatingSystem operatingSystem) {
26 | return downloadSource;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/UnknownVersion.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.util.ArchiveType;
4 | import io.arivera.oss.embedded.rabbitmq.util.OperatingSystem;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * A class that represents the RabbitMQ Version that is downloaded from the {@link SingleArtifactRepository}.
10 | *
11 | * The only thing we care about from the custom download artifact is the folder name where the RabbitMQ installation
12 | * can be found. We don't care about the version number, the Erlang version required, etc.
13 | */
14 | class UnknownVersion implements Version {
15 |
16 | private final String appFolderName;
17 |
18 | public UnknownVersion(String appFolderName) {
19 | this.appFolderName = appFolderName;
20 | }
21 |
22 | @Override
23 | public String getExtractionFolder() {
24 | return appFolderName;
25 | }
26 |
27 | @Override
28 | public String getMinimumErlangVersion() {
29 | return ErlangVersion.UNKNOWN;
30 | }
31 |
32 | @Override
33 | public String getVersionAsString() {
34 | throw new RuntimeException("This value isn't needed for custom downloads.");
35 | }
36 |
37 | @Override
38 | public String getVersionAsString(CharSequence separator) {
39 | throw new RuntimeException("This value isn't needed for custom downloads.");
40 | }
41 |
42 | @Override
43 | public ArchiveType getArchiveType(OperatingSystem operatingSystem) {
44 | throw new RuntimeException("This value isn't needed for custom downloads.");
45 | }
46 |
47 | @Override
48 | public List getVersionComponents() {
49 | throw new RuntimeException("This isn't needed for custom downloads.");
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/Version.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.util.ArchiveType;
4 | import io.arivera.oss.embedded.rabbitmq.util.OperatingSystem;
5 |
6 | import java.io.Serializable;
7 | import java.util.Comparator;
8 | import java.util.List;
9 |
10 | /**
11 | * A class that provides information about a specific distribution artifact version of RabbitMQ.
12 | */
13 | public interface Version {
14 |
15 | VersionComparator VERSION_COMPARATOR = new VersionComparator();
16 |
17 | /**
18 | * @return a String formatted like {@code "3.6.5"}
19 | *
20 | * @see #getVersionAsString(CharSequence)
21 | */
22 | String getVersionAsString();
23 |
24 | /**
25 | * @return a String formatted like {@code "3_6_5"} if given {@code "_"} as separator.
26 | */
27 | String getVersionAsString(CharSequence separator);
28 |
29 |
30 | /**
31 | * @return correct Archive Type for the given OS.
32 | */
33 | ArchiveType getArchiveType(OperatingSystem operatingSystem);
34 |
35 | /**
36 | * @return folder name under which the compressed application is extracted to.
37 | */
38 | String getExtractionFolder();
39 |
40 | /**
41 | * @return minimum version required to run this RabbitMQ version. Example: {@code "R16B3"} or {code null}
42 | */
43 | String getMinimumErlangVersion();
44 |
45 | /**
46 | * @return an Array like [3,6,5] for version 3.6.5
47 | */
48 | List getVersionComponents();
49 |
50 | class VersionComparator implements Comparator, Serializable {
51 |
52 | private static final long serialVersionUID = 1L;
53 |
54 | @Override
55 | public int compare(Version v1, Version v2) {
56 | for (int i = 0; i < v1.getVersionComponents().size(); i++) {
57 | int comp = v1.getVersionComponents().get(i).compareTo(v2.getVersionComponents().get(i));
58 | if (comp != 0) {
59 | return comp;
60 | }
61 | }
62 | return 0;
63 | }
64 |
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/apache/commons/io/FileUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package io.arivera.oss.embedded.rabbitmq.apache.commons.io;
18 |
19 | import java.io.File;
20 | import java.io.FileOutputStream;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.io.OutputStream;
24 | import java.net.Proxy;
25 | import java.net.URL;
26 | import java.net.URLConnection;
27 |
28 | /**
29 | * General file manipulation utilities.
30 | *
31 | * Facilities are provided in the following areas:
32 | *
33 | * - writing to a file
34 | *
- reading from a file
35 | *
- make a directory including parent directories
36 | *
- copying files and directories
37 | *
- deleting files and directories
38 | *
- converting to and from a URL
39 | *
- listing files and directories by filter and extension
40 | *
- comparing file content
41 | *
- file last changed date
42 | *
- calculating a checksum
43 | *
44 | *
45 | * Note that a specific charset should be specified whenever possible.
46 | * Relying on the platform default means that the code is Locale-dependent.
47 | * Only use the default if the files are known to always use the platform default.
48 | *
49 | * Origin of code: Excalibur, Alexandria, Commons-Utils
50 | *
51 | * @version $Id$
52 | */
53 | @SuppressWarnings("all")
54 | public class FileUtils {
55 |
56 | /**
57 | * Copies bytes from the URL source
to a file
58 | * destination
. The directories up to destination
59 | * will be created if they don't already exist. destination
60 | * will be overwritten if it already exists.
61 | *
62 | * @param source the URL
to copy bytes from, must not be {@code null}
63 | * @param destination the non-directory File
to write bytes to
64 | * (possibly overwriting), must not be {@code null}
65 | * @param connectionTimeout the number of milliseconds until this method
66 | * will timeout if no connection could be established to the source
67 | * @param readTimeout the number of milliseconds until this method will
68 | * timeout if no data could be read from the source
69 | * @throws IOException if source
URL cannot be opened
70 | * @throws IOException if destination
is a directory
71 | * @throws IOException if destination
cannot be written
72 | * @throws IOException if destination
needs creating but can't be
73 | * @throws IOException if an IO error occurs during copying
74 | * @since 2.0
75 | */
76 | public static void copyURLToFile(URL source, File destination,
77 | int connectionTimeout, int readTimeout) throws IOException {
78 | copyUrlToFile(source, destination, connectionTimeout, readTimeout, null);
79 | }
80 |
81 | /**
82 | * Copies bytes from the URL source
to a file
83 | * destination
. The directories up to destination
84 | * will be created if they don't already exist. destination
85 | * will be overwritten if it already exists.
86 | *
87 | * @param source the URL
to copy bytes from, must not be {@code null}
88 | * @param destination the non-directory File
to write bytes to
89 | * (possibly overwriting), must not be {@code null}
90 | * @param connectionTimeout the number of milliseconds until this method
91 | * will timeout if no connection could be established to the source
92 | * @param readTimeout the number of milliseconds until this method will
93 | * timeout if no data could be read from the source
94 | * @param proxy the proxy to use to open connection
95 | * @throws IOException if source
URL cannot be opened
96 | * @throws IOException if destination
is a directory
97 | * @throws IOException if destination
cannot be written
98 | * @throws IOException if destination
needs creating but can't be
99 | * @throws IOException if an IO error occurs during copying
100 | */
101 | public static void copyUrlToFile(URL source, File destination,
102 | int connectionTimeout, int readTimeout, Proxy proxy) throws IOException {
103 | URLConnection connection;
104 | if (proxy == null) {
105 | connection = source.openConnection();
106 | } else {
107 | connection = source.openConnection(proxy);
108 | }
109 | connection.setConnectTimeout(connectionTimeout);
110 | connection.setReadTimeout(readTimeout);
111 | InputStream input = connection.getInputStream();
112 | copyInputStreamToFile(input, destination);
113 | }
114 |
115 | /**
116 | * Copies bytes from an {@link InputStream} source
to a file
117 | * destination
. The directories up to destination
118 | * will be created if they don't already exist. destination
119 | * will be overwritten if it already exists.
120 | *
121 | * @param source the InputStream
to copy bytes from, must not be {@code null}
122 | * @param destination the non-directory File
to write bytes to
123 | * (possibly overwriting), must not be {@code null}
124 | * @throws IOException if destination
is a directory
125 | * @throws IOException if destination
cannot be written
126 | * @throws IOException if destination
needs creating but can't be
127 | * @throws IOException if an IO error occurs during copying
128 | * @since 2.0
129 | */
130 | public static void copyInputStreamToFile(InputStream source, File destination) throws IOException {
131 | try {
132 | FileOutputStream output = openOutputStream(destination);
133 | try {
134 | copy(source, output);
135 | output.close(); // don't swallow close Exception if copy completes normally
136 | } finally {
137 | closeQuietly(output);
138 | }
139 | } finally {
140 | closeQuietly(source);
141 | }
142 | }
143 |
144 |
145 | public static FileOutputStream openOutputStream(File file) throws IOException {
146 | if (file.exists()) {
147 | if (file.isDirectory()) {
148 | throw new IOException("File \'" + file + "\' exists but is a directory");
149 | }
150 |
151 | if (!file.canWrite()) {
152 | throw new IOException("File \'" + file + "\' cannot be written to");
153 | }
154 | } else {
155 | File parent = file.getParentFile();
156 | if (parent != null && !parent.exists() && !parent.mkdirs()) {
157 | throw new IOException("File \'" + file + "\' could not be created");
158 | }
159 | }
160 |
161 | return new FileOutputStream(file);
162 | }
163 |
164 | public static int copy(InputStream input, OutputStream output) throws IOException {
165 | long count = copyLarge(input, output);
166 | return count > 2147483647L ? -1 : (int) count;
167 | }
168 |
169 | public static long copyLarge(InputStream input, OutputStream output) throws IOException {
170 | byte[] buffer = new byte[4096];
171 | long count = 0L;
172 |
173 | int n1;
174 | for (boolean n = false; -1 != (n1 = input.read(buffer)); count += (long) n1) {
175 | output.write(buffer, 0, n1);
176 | }
177 |
178 | return count;
179 | }
180 |
181 |
182 | public static void closeQuietly(OutputStream output) {
183 | try {
184 | if (output != null) {
185 | output.close();
186 | }
187 | } catch (IOException var2) {
188 | ;
189 | }
190 |
191 | }
192 |
193 | public static void closeQuietly(InputStream input) {
194 | try {
195 | if (input != null) {
196 | input.close();
197 | }
198 | } catch (IOException var2) {
199 | ;
200 | }
201 |
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/apache/commons/lang3/JavaVersion.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package io.arivera.oss.embedded.rabbitmq.apache.commons.lang3;
18 |
19 | /**
20 | *
An enum representing all the versions of the Java specification.
21 | * This is intended to mirror available values from the
22 | * java.specification.version System property.
23 | *
24 | * @since 3.0
25 | */
26 | @SuppressWarnings("all")
27 | public enum JavaVersion {
28 |
29 | /**
30 | * The Java version reported by Android. This is not an official Java version number.
31 | */
32 | JAVA_0_9(1.5f, "0.9"),
33 |
34 | /**
35 | * Java 1.1.
36 | */
37 | JAVA_1_1(1.1f, "1.1"),
38 |
39 | /**
40 | * Java 1.2.
41 | */
42 | JAVA_1_2(1.2f, "1.2"),
43 |
44 | /**
45 | * Java 1.3.
46 | */
47 | JAVA_1_3(1.3f, "1.3"),
48 |
49 | /**
50 | * Java 1.4.
51 | */
52 | JAVA_1_4(1.4f, "1.4"),
53 |
54 | /**
55 | * Java 1.5.
56 | */
57 | JAVA_1_5(1.5f, "1.5"),
58 |
59 | /**
60 | * Java 1.6.
61 | */
62 | JAVA_1_6(1.6f, "1.6"),
63 |
64 | /**
65 | * Java 1.7.
66 | */
67 | JAVA_1_7(1.7f, "1.7"),
68 |
69 | /**
70 | * Java 1.8.
71 | */
72 | JAVA_1_8(1.8f, "1.8"),
73 |
74 | /**
75 | * Java 1.9.
76 | */
77 | JAVA_1_9(1.9f, "1.9"),
78 |
79 | /**
80 | * Java 1.x, x > 9. Mainly introduced to avoid to break when a new version of Java is used.
81 | */
82 | JAVA_RECENT(maxVersion(), Float.toString(maxVersion()));
83 |
84 | /**
85 | * The float value.
86 | */
87 | private final float value;
88 | /**
89 | * The standard name.
90 | */
91 | private final String name;
92 |
93 | /**
94 | * Constructor.
95 | *
96 | * @param value the float value
97 | * @param name the standard name, not null
98 | */
99 | JavaVersion(final float value, final String name) {
100 | this.value = value;
101 | this.name = name;
102 | }
103 |
104 | //-----------------------------------------------------------------------
105 | /**
106 | * Whether this version of Java is at least the version of Java passed in.
107 | *
108 | * For example:
109 | * {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}
110 | *
111 | * @param requiredVersion the version to check against, not null
112 | * @return true if this version is equal to or greater than the specified version
113 | */
114 | public boolean atLeast(final JavaVersion requiredVersion) {
115 | return this.value >= requiredVersion.value;
116 | }
117 |
118 | /**
119 | * Transforms the given string with a Java version number to the
120 | * corresponding constant of this enumeration class. This method is used
121 | * internally.
122 | *
123 | * @param nom the Java version as string
124 | * @return the corresponding enumeration constant or null if the
125 | * version is unknown
126 | */
127 | // helper for static importing
128 | static JavaVersion getJavaVersion(final String nom) {
129 | return get(nom);
130 | }
131 |
132 | /**
133 | * Transforms the given string with a Java version number to the
134 | * corresponding constant of this enumeration class. This method is used
135 | * internally.
136 | *
137 | * @param nom the Java version as string
138 | * @return the corresponding enumeration constant or null if the
139 | * version is unknown
140 | */
141 | static JavaVersion get(final String nom) {
142 | if ("0.9".equals(nom)) {
143 | return JAVA_0_9;
144 | } else if ("1.1".equals(nom)) {
145 | return JAVA_1_1;
146 | } else if ("1.2".equals(nom)) {
147 | return JAVA_1_2;
148 | } else if ("1.3".equals(nom)) {
149 | return JAVA_1_3;
150 | } else if ("1.4".equals(nom)) {
151 | return JAVA_1_4;
152 | } else if ("1.5".equals(nom)) {
153 | return JAVA_1_5;
154 | } else if ("1.6".equals(nom)) {
155 | return JAVA_1_6;
156 | } else if ("1.7".equals(nom)) {
157 | return JAVA_1_7;
158 | } else if ("1.8".equals(nom)) {
159 | return JAVA_1_8;
160 | } else if ("1.9".equals(nom)) {
161 | return JAVA_1_9;
162 | }
163 | if (nom == null) {
164 | return null;
165 | }
166 | final float v = toFloatVersion(nom);
167 | if ((v - 1.) < 1.) { // then we need to check decimals > .9
168 | final int firstComma = Math.max(nom.indexOf('.'), nom.indexOf(','));
169 | final int end = Math.max(nom.length(), nom.indexOf(',', firstComma));
170 | if (Float.parseFloat(nom.substring(firstComma + 1, end)) > .9f) {
171 | return JAVA_RECENT;
172 | }
173 | }
174 | return null;
175 | }
176 |
177 | //-----------------------------------------------------------------------
178 | /**
179 | *
The string value is overridden to return the standard name.
180 | *
181 | * For example, "1.5"
.
182 | *
183 | * @return the name, not null
184 | */
185 | @Override
186 | public String toString() {
187 | return name;
188 | }
189 |
190 | /**
191 | * Gets the Java Version from the system or 2.0 if the {@code java.version} system property is not set.
192 | *
193 | * @return the value of {@code java.version} system property or 2.0 if it is not set.
194 | */
195 | private static float maxVersion() {
196 | final float v = toFloatVersion(System.getProperty("java.version", "2.0"));
197 | if (v > 0) {
198 | return v;
199 | }
200 | return 2f;
201 | }
202 |
203 | /**
204 | * Parses a float value from a String.
205 | *
206 | * @param value the String to parse.
207 | * @return the float value represented by teh string or -1 if the given String can not be parsed.
208 | */
209 | private static float toFloatVersion(final String value) {
210 | final String[] toParse = value.split("\\.");
211 | if (toParse.length >= 2) {
212 | try {
213 | return Float.parseFloat(toParse[0] + '.' + toParse[1]);
214 | } catch (final NumberFormatException nfe) {
215 | // no-op, let use default
216 | }
217 | }
218 | return -1;
219 | }
220 | }
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/ErlangShell.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.zeroturnaround.exec.ProcessExecutor;
8 | import org.zeroturnaround.exec.ProcessResult;
9 | import org.zeroturnaround.exec.stream.slf4j.Level;
10 | import org.zeroturnaround.exec.stream.slf4j.Slf4jStream;
11 |
12 | import java.io.IOException;
13 | import java.util.concurrent.TimeUnit;
14 | import java.util.concurrent.TimeoutException;
15 |
16 | /**
17 | * A wrapper for the command "{@value ErlangShell#UNIX_ERL_COMMAND}
", used for checking/testing the Erlang version.
18 | */
19 | public class ErlangShell {
20 | private static final String LOGGER_TEMPLATE = "%s.Process.%s";
21 |
22 | private static final String UNIX_ERL_COMMAND = "erl";
23 |
24 | private final EmbeddedRabbitMqConfig config;
25 |
26 | /**
27 | * Generic Constructor.
28 | */
29 | public ErlangShell(final EmbeddedRabbitMqConfig config) {
30 | this.config = config;
31 |
32 | }
33 |
34 | /**
35 | * @return a String representing the Erlang version, such as {@code "18.2.1"}
36 | * @throws ErlangShellException if the Erlang command can't be executed or if it exits unexpectedly.
37 | */
38 | public String getErlangVersion() throws ErlangShellException {
39 | String erlangShell = UNIX_ERL_COMMAND;
40 |
41 | Logger processOutputLogger = LoggerFactory.getLogger(
42 | String.format(LOGGER_TEMPLATE, this.getClass().getName(), erlangShell));
43 |
44 | Slf4jStream stream = Slf4jStream.of(processOutputLogger);
45 |
46 | final ProcessExecutor processExecutor = config.getProcessExecutorFactory().createInstance()
47 | .command(erlangShell, "-noshell", "-eval", "erlang:display(erlang:system_info(otp_release)), halt().")
48 | .timeout(config.getErlangCheckTimeoutInMillis(), TimeUnit.MILLISECONDS)
49 | .redirectError(stream.as(Level.WARN))
50 | .destroyOnExit()
51 | .readOutput(true);
52 |
53 | try {
54 | ProcessResult processResult = processExecutor.execute();
55 | int exitValue = processResult.getExitValue();
56 | if (exitValue == 0) {
57 | return processResult.outputUTF8().trim().replaceAll("[\"\\\\n]", ""); // "18.2.1\n" -> "18.2.1"
58 | } else {
59 | throw new ErlangShellException("Erlang exited with status " + exitValue);
60 | }
61 | } catch (IOException | InterruptedException | TimeoutException e) {
62 | throw new ErlangShellException("Exception executing Erlang shell command", e);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/ErlangShellException.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | public class ErlangShellException extends Exception {
4 | public ErlangShellException(String message) {
5 | super(message);
6 | }
7 |
8 | public ErlangShellException(String message, Throwable cause) {
9 | super(message, cause);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/LoggingProcessListener.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.util.StringUtils;
4 |
5 | import org.slf4j.Logger;
6 | import org.zeroturnaround.exec.InvalidExitValueException;
7 | import org.zeroturnaround.exec.ProcessExecutor;
8 | import org.zeroturnaround.exec.ProcessResult;
9 | import org.zeroturnaround.exec.listener.ProcessListener;
10 |
11 | class LoggingProcessListener extends ProcessListener {
12 |
13 | private final Logger logger;
14 | private ProcessExecutor executor;
15 |
16 | LoggingProcessListener(Logger logger) {
17 | this.logger = logger;
18 | }
19 |
20 | @Override
21 | public void beforeStart(ProcessExecutor executor) {
22 | this.executor = executor;
23 | logger.debug("Executing '{}' with environment vars: {}",
24 | StringUtils.join(executor.getCommand(), " "), executor.getEnvironment());
25 | }
26 |
27 | @Override
28 | public void afterStart(Process process, ProcessExecutor executor) {
29 | logger.debug("Process started.");
30 | }
31 |
32 | @Override
33 | public void afterFinish(Process process, ProcessResult result) {
34 | assert executor != null; // "beforeStart()" must be called previously
35 | try {
36 | executor.checkExitValue(result);
37 | logger.debug("Process finished (exit code: {}).", result.getExitValue());
38 | } catch (InvalidExitValueException e) {
39 | logger.error("Process finished with unexpected exit code: {}.", result.getExitValue());
40 | }
41 | }
42 |
43 | @Override
44 | public void afterStop(Process process) {
45 | logger.debug("Process stopped");
46 | }
47 | }
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/RabbitMqCommand.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMq;
4 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
5 | import io.arivera.oss.embedded.rabbitmq.apache.commons.lang3.SystemUtils;
6 | import io.arivera.oss.embedded.rabbitmq.util.StringUtils;
7 |
8 | import org.apache.commons.io.output.NullOutputStream;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.zeroturnaround.exec.ProcessExecutor;
12 | import org.zeroturnaround.exec.StartedProcess;
13 | import org.zeroturnaround.exec.listener.ProcessListener;
14 | import org.zeroturnaround.exec.stream.slf4j.Level;
15 | import org.zeroturnaround.exec.stream.slf4j.Slf4jStream;
16 |
17 | import java.io.File;
18 | import java.io.IOException;
19 | import java.io.OutputStream;
20 | import java.util.ArrayList;
21 | import java.util.Arrays;
22 | import java.util.List;
23 | import java.util.Map;
24 | import java.util.concurrent.Callable;
25 |
26 | /**
27 | * A generic way of executing any of the commands found under the {@code sbin} folder of the RabbitMQ installation.
28 | *
29 | * Example usage:
30 | *
RabbitMqCommand command = new RabbitMqCommand(config, "rabbitmq-server", "-detached");
31 | * StartedProcess process = command.call();
32 | * // ...
33 | *
34 | *
35 | *
36 | * To read the output as it happens, use the {@link #writeOutputTo(OutputStream)} method.
37 | *
38 | * To be notified of the process ending without blocking for the result of the finished process, use
39 | * {@link #listenToEvents(ProcessListener)} method.
40 | *
41 | * @see RabbitMqCtl
42 | * @see RabbitMqServer
43 | */
44 | public class RabbitMqCommand implements Callable {
45 |
46 | static final String BINARIES_FOLDER = "sbin";
47 |
48 | private static final String LOGGER_TEMPLATE = "%s.Process.%s";
49 |
50 | private static final ProcessListener NULL_LISTENER = new NullProcessListener();
51 | private static final NullOutputStream NULL_OUTPUT_STREAM = new NullOutputStream();
52 |
53 | private static final boolean IS_WIN = SystemUtils.IS_OS_WINDOWS;
54 | private static final String WIN_EXT = ".bat";
55 | private static final String UNIT_EXT = "";
56 |
57 | private final String command;
58 | private final File executableFile;
59 | private final List arguments;
60 |
61 | private final ProcessExecutorFactory processExecutorFactory;
62 | private final File appFolder;
63 | private final Map envVars;
64 |
65 | private Logger processOutputLogger;
66 | private OutputStream outputStream;
67 | private OutputStream errorOutputStream;
68 | private ProcessListener eventsListener;
69 | private boolean storeOutput;
70 | private Level stdOutLogLevel;
71 | private Level stdErrLogLevel;
72 |
73 | /**
74 | * Constructs a new instance this class to execute arbitrary RabbitMQ commands with arbitrary arguments.
75 | *
76 | * By default:
77 | *
99 | *
100 | * @param config the configuration information used to launch the process with the correct context.
101 | * @param command command name, without any path or extension. For example, for a command like
102 | * "{@code rabbitmq-plugins.bat list}", use "{@code rabbitmq-plugins}" as value
103 | * @param arguments list of arguments to pass to the executable. For example, for a command like
104 | * "{@code ./rabbitmq-plugins enable foo}", utilize {@code ["enable", "foo"]} as value
105 | */
106 | public RabbitMqCommand(EmbeddedRabbitMqConfig config, String command, String... arguments) {
107 | this(config.getProcessExecutorFactory(), config.getEnvVars(), config.getAppFolder(), command, arguments);
108 | }
109 |
110 | /**
111 | * An alternative constructor that allows for more control.
112 | */
113 | public RabbitMqCommand(ProcessExecutorFactory processExecutorFactory, Map envVars, File appFolder,
114 | String command, String... arguments) {
115 | this.processExecutorFactory = processExecutorFactory;
116 | this.command = command + getCommandExtension();
117 | this.envVars = envVars;
118 | this.appFolder = appFolder;
119 | this.executableFile = new File(new File(this.appFolder, BINARIES_FOLDER), this.command);
120 | if (!(executableFile.exists())) {
121 | throw new IllegalArgumentException("The given command could not be found using the path: " + executableFile);
122 | }
123 |
124 | this.arguments = Arrays.asList(arguments);
125 | this.processOutputLogger = LoggerFactory.getLogger(
126 | String.format(LOGGER_TEMPLATE, EmbeddedRabbitMq.class.getName(), command));
127 |
128 | this.outputStream = NULL_OUTPUT_STREAM;
129 | this.errorOutputStream = NULL_OUTPUT_STREAM;
130 | this.eventsListener = NULL_LISTENER;
131 |
132 | this.storeOutput = true;
133 | this.stdOutLogLevel = Level.INFO;
134 | this.stdErrLogLevel = Level.WARN;
135 | }
136 |
137 | static String getCommandExtension() {
138 | return IS_WIN ? WIN_EXT : UNIT_EXT;
139 | }
140 |
141 | /**
142 | * Output from the process will be written here as it happens.
143 | *
144 | * @see #writeErrorOutputTo(OutputStream)
145 | */
146 | public RabbitMqCommand writeOutputTo(OutputStream outputStream) {
147 | this.outputStream = outputStream;
148 | return this;
149 | }
150 |
151 | /**
152 | * Error output from the process will be written here as it happens.
153 | *
154 | * @see #writeOutputTo(OutputStream)
155 | */
156 | public RabbitMqCommand writeErrorOutputTo(OutputStream outputStream) {
157 | this.errorOutputStream = outputStream;
158 | return this;
159 | }
160 |
161 | /**
162 | * Defines which SLF4J logger to use log the process output as it would have been dumped to STDOUT and STDERR.
163 | */
164 | public RabbitMqCommand logWith(Logger logger) {
165 | this.processOutputLogger = logger;
166 | return this;
167 | }
168 |
169 | /**
170 | * Registers a unique listener to be notified of process events, such as start and finish.
171 | */
172 | public RabbitMqCommand listenToEvents(ProcessListener listener) {
173 | this.eventsListener = listener;
174 | return this;
175 | }
176 |
177 | /**
178 | * Used to define if the output of the process should be stored for retrieval after the ProcessResult future is
179 | * completed.
180 | *
181 | * Default is {@code true}
182 | */
183 | public RabbitMqCommand storeOutput(boolean storeOutput) {
184 | this.storeOutput = storeOutput;
185 | return this;
186 | }
187 |
188 | /**
189 | * Defines which logging level to use for the process' standard output.
190 | *
191 | * Default is {@code INFO}
192 | */
193 | public RabbitMqCommand logStandardOutputAs(Level level) {
194 | this.stdOutLogLevel = level;
195 | return this;
196 | }
197 |
198 | /**
199 | * Defines which logging level to use for the processes' standard error output.
200 | *
201 | * Default is {@code WARN}
202 | */
203 | public RabbitMqCommand logStandardErrorOutputAs(Level level) {
204 | this.stdErrLogLevel = level;
205 | return this;
206 | }
207 |
208 | @Override
209 | public StartedProcess call() throws RabbitMqCommandException {
210 |
211 | List fullCommand = new ArrayList<>(arguments);
212 | fullCommand.add(0, executableFile.toString());
213 |
214 | Slf4jStream loggingStream = Slf4jStream.of(processOutputLogger);
215 | LoggingProcessListener loggingListener = new LoggingProcessListener(processOutputLogger);
216 |
217 | ProcessExecutor processExecutor = processExecutorFactory.createInstance()
218 | .environment(envVars)
219 | .directory(appFolder)
220 | .command(fullCommand)
221 | .destroyOnExit()
222 | .addListener(loggingListener) // Logs process events (like start, stop...)
223 | .addListener(eventsListener) // Notifies asynchronously of process events (start/finish/stop)
224 | .redirectError(loggingStream.as(stdErrLogLevel)) // Logging for output made to STDERR
225 | .redirectOutput(loggingStream.as(stdOutLogLevel)) // Logging for output made to STDOUT
226 | .redirectOutputAlsoTo(outputStream) // Pipe stdout to this stream for the application to process
227 | .redirectErrorAlsoTo(errorOutputStream) // Pipe stderr to this stream for the application to process
228 | .readOutput(storeOutput); // Store the output in the ProcessResult as well.
229 |
230 | try {
231 | return processExecutor.start();
232 | } catch (IOException e) {
233 | throw new RabbitMqCommandException("Failed to execute: " + StringUtils.join(fullCommand, " "), e);
234 | }
235 | }
236 |
237 | public static class ProcessExecutorFactory {
238 | public ProcessExecutor createInstance() {
239 | return new ProcessExecutor();
240 | }
241 | }
242 |
243 | private static class NullProcessListener extends ProcessListener {
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/RabbitMqCommandException.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | public class RabbitMqCommandException extends RuntimeException {
4 |
5 | public RabbitMqCommandException(String message) {
6 | super(message);
7 | }
8 |
9 | public RabbitMqCommandException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/RabbitMqCtl.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | import org.zeroturnaround.exec.ProcessResult;
6 |
7 | import java.io.File;
8 | import java.util.Map;
9 | import java.util.Set;
10 | import java.util.concurrent.Future;
11 |
12 | /**
13 | * This is a helper class meant to facilitate invoking commands from {@code rabbitmqctl}.
14 | *
15 | * The methods contained in this class aren't exhaustive. Please refer to the manual for a complete list.
16 | *
17 | * @see rabbitmqctl(8) manual page
18 | */
19 | public class RabbitMqCtl extends RabbitMqDiagnostics {
20 |
21 | public static final String COMMAND = "rabbitmqctl";
22 |
23 | public RabbitMqCtl(EmbeddedRabbitMqConfig config) {
24 | super(config);
25 | }
26 |
27 | public RabbitMqCtl(EmbeddedRabbitMqConfig config, Map extraEnvVars) {
28 | super(config, extraEnvVars);
29 | }
30 |
31 | public RabbitMqCtl(EmbeddedRabbitMqConfig config, Set envVarsToDiscard, Map envVarsToAdd) {
32 | super(config, envVarsToDiscard, envVarsToAdd);
33 | }
34 |
35 | public RabbitMqCtl(RabbitMqCommand.ProcessExecutorFactory processExecutorFactory, File appFolder,
36 | Map envVars) {
37 | super(processExecutorFactory, appFolder, envVars);
38 | }
39 |
40 | /**
41 | * Stops the Erlang node on which RabbitMQ is running.
42 | */
43 | public Future stop() throws RabbitMqCommandException {
44 | return execute("stop");
45 | }
46 |
47 | /**
48 | * Stops the RabbitMQ application, leaving the Erlang node running.
49 | *
50 | * This command is typically run prior to performing other management actions that require the
51 | * RabbitMQ application to be stopped, e.g. {@link #reset()}.
52 | */
53 | public Future stopApp() throws RabbitMqCommandException {
54 | return execute("stop_app");
55 | }
56 |
57 | /**
58 | * Starts the RabbitMQ application.
59 | *
60 | * This command is typically run after performing other management actions that required the
61 | * RabbitMQ application to be stopped, e.g. {@link #reset()}.
62 | */
63 | public Future startApp() throws RabbitMqCommandException {
64 | return execute("start_app");
65 | }
66 |
67 | /**
68 | * Return a RabbitMQ node to its virgin state.
69 | *
70 | * Removes the node from any cluster it belongs to, removes all data from the management database,
71 | * such as configured users and vhosts, and deletes all persistent messages.
72 | *
73 | * For reset and force_reset to succeed the RabbitMQ application must have been stopped, e.g. with {@link #stopApp()}
74 | */
75 | public Future reset() throws RabbitMqCommandException {
76 | return execute("reset");
77 | }
78 |
79 | /**
80 | * Forcefully return a RabbitMQ node to its virgin state.
81 | *
82 | * The force_reset command differs from reset in that it resets the node unconditionally,
83 | * regardless of the current management database state and cluster configuration.
84 | * It should only be used as a last resort if the database or cluster configuration has been corrupted.
85 | *
86 | * For reset and force_reset to succeed the RabbitMQ application must have been stopped, e.g. with {@link #stopApp()}
87 | */
88 | public Future forceReset() throws RabbitMqCommandException {
89 | return execute("force_reset");
90 | }
91 |
92 | @Override
93 | protected String getCommand() {
94 | return COMMAND;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/RabbitMqDiagnostics.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | import org.zeroturnaround.exec.ProcessResult;
6 |
7 | import java.io.File;
8 | import java.util.Arrays;
9 | import java.util.Collections;
10 | import java.util.HashMap;
11 | import java.util.HashSet;
12 | import java.util.Map;
13 | import java.util.Set;
14 | import java.util.concurrent.Future;
15 |
16 | /**
17 | * This is a helper class meant to facilitate invoking commands from {@code rabbitmq-diagnostics}.
18 | *
19 | * @see rabbitmq-diagnostics(8) manual page
20 | */
21 | public class RabbitMqDiagnostics {
22 |
23 | /**
24 | * Default list of Environment Variables to discard from {@link EmbeddedRabbitMqConfig#getEnvVars()}, as
25 | * it is known that some of them cause conflicts when executing commands.
26 | */
27 | private static final Set DEFAULT_ENV_VARS_TO_DISCARD = new HashSet<>(Arrays.asList("RABBITMQ_NODE_PORT"));
28 | private static final String COMMAND = "rabbitmq-diagnostics";
29 |
30 | private RabbitMqCommand.ProcessExecutorFactory peFactory;
31 | private File appFolder;
32 | private Map envVars;
33 |
34 | public RabbitMqDiagnostics(EmbeddedRabbitMqConfig config) {
35 | this(config, Collections.EMPTY_MAP);
36 | }
37 |
38 | /**
39 | * A constructor that allows additional env vars while also discarding default known vars that cause issues.
40 | *
41 | * @see #DEFAULT_ENV_VARS_TO_DISCARD
42 | */
43 | public RabbitMqDiagnostics(EmbeddedRabbitMqConfig config, Map extraEnvVars) {
44 | this(config, DEFAULT_ENV_VARS_TO_DISCARD, extraEnvVars);
45 | }
46 |
47 | /**
48 | * A constructor that allows additional env vars while also allowing to override the default env vars to discard.
49 | *
50 | * @see #DEFAULT_ENV_VARS_TO_DISCARD
51 | */
52 | public RabbitMqDiagnostics(EmbeddedRabbitMqConfig config,
53 | Set envVarsToDiscard,
54 | Map envVarsToAdd) {
55 | this(config.getProcessExecutorFactory(), config.getAppFolder(),
56 | mapFilterAndAppend(config.getEnvVars(), envVarsToDiscard, envVarsToAdd));
57 | }
58 |
59 | /**
60 | * Full-fledged constructor.
61 | */
62 | public RabbitMqDiagnostics(RabbitMqCommand.ProcessExecutorFactory processExecutorFactory,
63 | File appFolder, Map envVars) {
64 | this.peFactory = processExecutorFactory;
65 | this.appFolder = appFolder;
66 | this.envVars = envVars;
67 | }
68 |
69 | protected static Map mapFilterAndAppend(Map envVars,
70 | Set envVarsToDiscard,
71 | Map envVarsToAdd) {
72 | Map tmpEnvVars = envVars;
73 | if (!envVarsToDiscard.isEmpty() || envVarsToAdd.isEmpty()) {
74 | tmpEnvVars = new HashMap<>(tmpEnvVars);
75 | for (String var : envVarsToDiscard) {
76 | tmpEnvVars.remove(var);
77 | }
78 | tmpEnvVars.putAll(envVarsToAdd);
79 | }
80 | return tmpEnvVars;
81 | }
82 |
83 | /**
84 | * This method exposes a way to invoke a command with any arguments. This is useful when the class methods
85 | * don't expose the desired functionality.
86 | *
87 | * For example:
88 | *
89 | * RabbitMqDiagnostics command = new RabbitMqDiagnostics(config);
90 | * command.execute("list_users");
91 | *
92 | */
93 | public Future execute(String... arguments) throws RabbitMqCommandException {
94 | return new RabbitMqCommand(peFactory, envVars, appFolder, getCommand(), arguments)
95 | .call()
96 | .getFuture();
97 | }
98 |
99 | protected String getCommand() {
100 | return COMMAND;
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/RabbitMqPlugins.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 | import io.arivera.oss.embedded.rabbitmq.bin.plugins.Plugin;
5 |
6 | import org.zeroturnaround.exec.ProcessResult;
7 |
8 | import java.io.File;
9 | import java.util.Collection;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 | import java.util.Set;
14 | import java.util.TreeSet;
15 | import java.util.concurrent.ExecutionException;
16 | import java.util.concurrent.Future;
17 | import java.util.concurrent.TimeUnit;
18 | import java.util.concurrent.TimeoutException;
19 |
20 | /**
21 | * This is a helper class meant to facilitate invoking commands from {@code rabbitmq-plugins}.
22 | *
23 | * @see rabbitmq-plugins(8) manual page
24 | */
25 | public class RabbitMqPlugins extends RabbitMqDiagnostics {
26 |
27 | private static final String LIST_COMMAND = "list";
28 | private static final String COMMAND = "rabbitmq-plugins";
29 |
30 | private final long timeoutInMillis;
31 |
32 | public RabbitMqPlugins(EmbeddedRabbitMqConfig config) {
33 | super(config);
34 | this.timeoutInMillis = config.getDefaultRabbitMqCtlTimeoutInMillis();
35 | }
36 |
37 | public RabbitMqPlugins(EmbeddedRabbitMqConfig config, Map extraEnvVars) {
38 | super(config, extraEnvVars);
39 | this.timeoutInMillis = config.getDefaultRabbitMqCtlTimeoutInMillis();
40 | }
41 |
42 | public RabbitMqPlugins(EmbeddedRabbitMqConfig config, Set envVarsToDiscard, Map envVarsToAdd) {
43 | super(config, envVarsToDiscard, envVarsToAdd);
44 | this.timeoutInMillis = config.getDefaultRabbitMqCtlTimeoutInMillis();
45 | }
46 |
47 | public RabbitMqPlugins(RabbitMqCommand.ProcessExecutorFactory processExecutorFactory, File appFolder,
48 | Map envVars, long timeoutInMillis) {
49 | super(processExecutorFactory, appFolder, envVars);
50 | this.timeoutInMillis = timeoutInMillis;
51 | }
52 |
53 | /**
54 | * Same as {@link #list()} but it returns the plugins grouped by state.
55 | */
56 | public Map> groupedList() throws RabbitMqCommandException {
57 | Collection plugins = list().values();
58 | return groupPluginsByState(plugins);
59 | }
60 |
61 | private Map> groupPluginsByState(Collection plugins) {
62 | Map> groupedPlugins = new HashMap<>();
63 | for (Plugin.State state : Plugin.State.values()) {
64 | groupedPlugins.put(state, new TreeSet());
65 | }
66 |
67 | for (Plugin plugin : plugins) {
68 | for (Plugin.State state : plugin.getState()) {
69 | groupedPlugins.get(state).add(plugin);
70 | }
71 | }
72 | return groupedPlugins;
73 | }
74 |
75 | /**
76 | * Executes the {@code rabbitmq-plugins list} command
77 | *
78 | * @return a Map where the key is the plugin name and the value is the full plugin details parsed from the output.
79 | *
80 | * @throws RabbitMqCommandException if the command cannot be executed, it doesn't
81 | * {@link EmbeddedRabbitMqConfig.Builder#defaultRabbitMqCtlTimeoutInMillis(long)
82 | * finish in time} or exits unexpectedly
83 | * @see #groupedList()
84 | */
85 | public Map list() {
86 | String[] args = {LIST_COMMAND};
87 | String executionErrorMessage = String.format("Error executing: %s %s", COMMAND, LIST_COMMAND);
88 | String unexpectedExitCodeMessage = "Listing of plugins failed with exit code: ";
89 |
90 | ProcessResult processResult = getProcessResult(args, executionErrorMessage, unexpectedExitCodeMessage);
91 |
92 | List plugins = parseListOutput(processResult);
93 | Map result = mapPluginsByName(plugins);
94 | return result;
95 | }
96 |
97 | private List parseListOutput(ProcessResult processResult) {
98 | List lines = processResult.getOutput().getLinesAsUTF8();
99 | return Plugin.fromStrings(lines);
100 | }
101 |
102 | private Map mapPluginsByName(List plugins) {
103 | Map result = new HashMap<>(plugins.size());
104 | for (Plugin plugin : plugins) {
105 | result.put(plugin.getName(), plugin);
106 | }
107 | return result;
108 | }
109 |
110 | /**
111 | * Executes the command {@code rabbitmq-plugins enable {plugin}} and blocks until the call finishes.
112 | *
113 | * @param plugin the name of the plugin to enable.
114 | *
115 | * @throws RabbitMqCommandException if the command cannot be executed, it doesn't
116 | * {@link EmbeddedRabbitMqConfig.Builder#defaultRabbitMqCtlTimeoutInMillis(long)
117 | * finish in time} or exits unexpectedly
118 | */
119 | public void enable(String plugin) throws RabbitMqCommandException {
120 | String[] args = {"enable", plugin};
121 | String executionErrorMessage = "Error while enabling plugin '" + plugin + "'";
122 | String unexpectedExitCodeMessage = "Enabling of plugin '" + plugin + "' failed with exit code: ";
123 |
124 | getProcessResult(args, executionErrorMessage, unexpectedExitCodeMessage);
125 | }
126 |
127 | /**
128 | * Disables the given plugin by executing {@code rabbitmq-plugins disable {plugin}} and blocks until the call is
129 | * finished.
130 | *
131 | * @param plugin the name of the plugin to disable.
132 | *
133 | * @throws RabbitMqCommandException if the command cannot be executed, it doesn't
134 | * {@link EmbeddedRabbitMqConfig.Builder#defaultRabbitMqCtlTimeoutInMillis(long)
135 | * finish in time} or exits unexpectedly
136 | */
137 | public void disable(String plugin) throws RabbitMqCommandException {
138 | String[] args = {"disable", plugin};
139 | String executionErrorMessage = "Error while disabling plugin '" + plugin + "'";
140 | String unexpectedExitCodeMessage = "Disabling of plugin '" + plugin + "' failed with exit code: ";
141 |
142 | getProcessResult(args, executionErrorMessage, unexpectedExitCodeMessage);
143 | }
144 |
145 | private ProcessResult getProcessResult(String[] args, String executionErrorMessage, String unexpectedExitCodeMessage) {
146 | ProcessResult processResult;
147 | try {
148 | Future startedProcess = execute(args);
149 | processResult = startedProcess.get(timeoutInMillis, TimeUnit.MILLISECONDS);
150 | } catch (InterruptedException | ExecutionException | TimeoutException e) {
151 | throw new RabbitMqCommandException(executionErrorMessage, e);
152 | }
153 |
154 | int exitValue = processResult.getExitValue();
155 | if (exitValue != 0) {
156 | throw new RabbitMqCommandException(unexpectedExitCodeMessage + exitValue);
157 | }
158 | return processResult;
159 | }
160 |
161 | @Override
162 | protected String getCommand() {
163 | return COMMAND;
164 | }
165 |
166 | }
167 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/RabbitMqServer.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | import org.apache.commons.io.output.NullOutputStream;
6 | import org.zeroturnaround.exec.ProcessResult;
7 | import org.zeroturnaround.exec.listener.ProcessListener;
8 |
9 | import java.io.OutputStream;
10 | import java.util.concurrent.Future;
11 |
12 | /**
13 | * A wrapper for the command "{@value RabbitMqServer#COMMAND}
", used for starting the RabbitMQ broker.
14 | */
15 | public class RabbitMqServer {
16 |
17 | private static final String COMMAND = "rabbitmq-server";
18 |
19 | private final EmbeddedRabbitMqConfig config;
20 |
21 | private OutputStream outputStream;
22 | private ProcessListener listener;
23 |
24 | /**
25 | * Creates a new RabbitMqServer with NOOP settings for output capturing and event listening.
26 | *
27 | * @see #writeOutputTo(OutputStream)
28 | * @see #listeningToEventsWith(ProcessListener)
29 | */
30 | public RabbitMqServer(EmbeddedRabbitMqConfig config) {
31 | this.config = config;
32 | this.outputStream = new NullOutputStream();
33 | this.listener = new NullProcessListener();
34 | }
35 |
36 | /**
37 | * Use this method if you wish the output of the process is streamed somewhere as it happens.
38 | *
39 | * @return this same instance of the class to allow for chaining calls.
40 | *
41 | * @see RabbitMqCommand#writeOutputTo(OutputStream)
42 | */
43 | public RabbitMqServer writeOutputTo(OutputStream outputStream) {
44 | this.outputStream = outputStream;
45 | return this;
46 | }
47 |
48 | /**
49 | * Use this method to register a listener to be notified of process events, like start, stop, etc.
50 | */
51 | public RabbitMqServer listeningToEventsWith(ProcessListener listener) {
52 | this.listener = listener;
53 | return this;
54 | }
55 |
56 | /**
57 | * Starts the RabbitMQ Server and keeps the process running until it's stopped.
58 | *
59 | * Running rabbitmq-server in the foreground displays a banner message, and reports on progress in the startup
60 | * sequence, concluding with the message "{@code completed with [N] plugins.}", indicating that the
61 | * RabbitMQ broker has been started successfully.
62 | *
63 | * To read the output, either:
64 | *
65 | * - wait for the returning Future to finish and use {@link ProcessResult} output getter methods, or
66 | * - provide an Output Stream through {@link #writeOutputTo(OutputStream)} to receive it as it happens.
67 | *
68 | *
69 | * To be notified of process events, such as the process starting or finishing, provide a
70 | */
71 | public Future start() throws RabbitMqCommandException {
72 | return execute();
73 | }
74 |
75 | /**
76 | * Start the RabbitMq Server in a detached state.
77 | *
78 | * This means the process will exit immediately and no PID file will be written to file.
79 | */
80 | public Future startDetached() throws RabbitMqCommandException {
81 | return execute("-detached");
82 | }
83 |
84 | private Future execute(String... arguments) throws RabbitMqCommandException {
85 | return new RabbitMqCommand(config, COMMAND, arguments)
86 | .writeOutputTo(outputStream)
87 | .listenToEvents(listener)
88 | .call()
89 | .getFuture();
90 | }
91 |
92 | private static class NullProcessListener extends ProcessListener {
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/bin/plugins/Plugin.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin.plugins;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Arrays;
8 | import java.util.Collection;
9 | import java.util.EnumSet;
10 | import java.util.List;
11 | import java.util.Objects;
12 | import java.util.regex.Matcher;
13 | import java.util.regex.Pattern;
14 |
15 | public class Plugin implements Comparable {
16 |
17 | static final Pattern LIST_OUTPUT_PATTERN = Pattern.compile("\\s*\\[(.*)]\\s+(\\w+)\\s+(\\S+)\\s*");
18 |
19 | private static final Logger LOGGER = LoggerFactory.getLogger(Plugin.class);
20 |
21 | private String pluginName;
22 | private EnumSet status;
23 | private String version;
24 |
25 | private Plugin(String pluginName, EnumSet state, String version) {
26 | this.pluginName = pluginName;
27 | this.status = state;
28 | this.version = version;
29 | }
30 |
31 | /**
32 | * @param strings all the lines to parse. Those that can't be parsed won't be part of the resulting list.
33 | */
34 | public static List fromStrings(Collection strings) {
35 | List plugins = new ArrayList<>(strings.size());
36 | for (String string : strings) {
37 | Plugin plugin = fromString(string);
38 | if (plugin != null) {
39 | plugins.add(plugin);
40 | }
41 | }
42 | return plugins;
43 | }
44 |
45 | /**
46 | * @param outputLine as generated by the command line {@code rabbitmq-plugins groupedList}
47 | *
48 | * @return null if output can't be parsed.
49 | */
50 | public static Plugin fromString(String outputLine) {
51 | Matcher matcher = LIST_OUTPUT_PATTERN.matcher(outputLine);
52 | if (!matcher.matches()) {
53 | return null;
54 | }
55 | String state = matcher.group(1);
56 | String pluginName = matcher.group(2);
57 | String version = matcher.group(3);
58 |
59 | return new Plugin(pluginName, State.fromString(state), version);
60 | }
61 |
62 | public String getName() {
63 | return pluginName;
64 | }
65 |
66 | public EnumSet getState() {
67 | return status;
68 | }
69 |
70 | public String getVersion() {
71 | return version;
72 | }
73 |
74 | @Override
75 | public boolean equals(Object other) {
76 | if (this == other) {
77 | return true;
78 | }
79 | if (other == null || getClass() != other.getClass()) {
80 | return false;
81 | }
82 | Plugin that = (Plugin) other;
83 | return Objects.equals(pluginName, that.pluginName);
84 | }
85 |
86 | @Override
87 | public int hashCode() {
88 | return Objects.hash(pluginName);
89 | }
90 |
91 | @Override
92 | public int compareTo(Plugin other) {
93 | return this.pluginName.compareTo(other.pluginName);
94 | }
95 |
96 | @Override
97 | public String toString() {
98 | final StringBuilder sb = new StringBuilder("Plugin{");
99 | sb.append("name='").append(pluginName).append('\'');
100 | sb.append(", status=").append(status);
101 | sb.append(", version='").append(version).append('\'');
102 | sb.append('}');
103 | return sb.toString();
104 | }
105 |
106 | public enum State {
107 | ENABLED_EXPLICITLY, ENABLED_IMPLICITLY, NOT_ENABLED,
108 | RUNNING, NOT_RUNNING;
109 |
110 | /**
111 | * Parses a string as given by the command line output from {@code rabbitmq-plugins list} for the characters in
112 | * between brackets.
113 | */
114 | public static EnumSet fromString(String string) {
115 | EnumSet pluginStatuses = EnumSet.noneOf(State.class);
116 |
117 | char[] chars = string.toCharArray();
118 |
119 | if (chars.length != 2) {
120 | LOGGER.warn("Parsing of Plugin State might not be accurate since we expect 2 symbols representing: {}",
121 | Arrays.asList(State.values()));
122 | }
123 |
124 | if (chars.length <= 0) {
125 | return pluginStatuses;
126 | }
127 |
128 | char enabledCharacter = chars[0];
129 | switch (enabledCharacter) {
130 | case ' ':
131 | pluginStatuses.add(NOT_ENABLED);
132 | break;
133 | case 'e':
134 | pluginStatuses.add(ENABLED_IMPLICITLY);
135 | break;
136 | case 'E':
137 | pluginStatuses.add(ENABLED_EXPLICITLY);
138 | break;
139 | default:
140 | LOGGER.warn("Could not parse symbol '{}' for enabled state in: {}", enabledCharacter, string);
141 | }
142 |
143 | if (chars.length < 2) {
144 | return pluginStatuses;
145 | }
146 |
147 | char runningCharacter = string.charAt(1);
148 | switch (runningCharacter) {
149 | case '*':
150 | pluginStatuses.add(RUNNING);
151 | break;
152 | case ' ':
153 | pluginStatuses.add(NOT_RUNNING);
154 | break;
155 | default:
156 | LOGGER.warn("Could not parse symbol '{}' for run state in: {}", runningCharacter, string);
157 | }
158 |
159 | return pluginStatuses;
160 | }
161 |
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/download/BasicDownloader.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.download;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 | import io.arivera.oss.embedded.rabbitmq.apache.commons.io.FileUtils;
5 | import io.arivera.oss.embedded.rabbitmq.apache.commons.lang3.StopWatch;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.io.IOException;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.concurrent.Semaphore;
14 |
15 | class BasicDownloader implements Runnable, Downloader {
16 |
17 | private static final Logger LOGGER = LoggerFactory.getLogger(BasicDownloader.class);
18 |
19 | private final EmbeddedRabbitMqConfig config;
20 |
21 | BasicDownloader(EmbeddedRabbitMqConfig config) {
22 | this.config = config;
23 | }
24 |
25 | @Override
26 | public void run() throws DownloadException {
27 | DownloadProgressNotifier progressNotifier = new DownloadProgressNotifier(config);
28 | DownloadTask downloadTask = new DownloadTask(config);
29 | downloadTask.addListener(progressNotifier);
30 |
31 | Thread notifierThread = new Thread(progressNotifier, "RabbitMQ-Download-Watcher");
32 | notifierThread.start();
33 | downloadTask.run();
34 | }
35 |
36 | private static class DownloadTask implements Runnable {
37 | private final StopWatch stopWatch;
38 | private final EmbeddedRabbitMqConfig config;
39 | private final List downloadListeners;
40 |
41 | public DownloadTask(EmbeddedRabbitMqConfig config) {
42 | this.config = config;
43 | this.stopWatch = new StopWatch();
44 | this.downloadListeners = new ArrayList<>();
45 | }
46 |
47 | public void addListener(DownloadListener downloadListener) {
48 | this.downloadListeners.add(downloadListener);
49 | }
50 |
51 | public void run() {
52 | LOGGER.info("Downloading '{}'...", config.getDownloadSource());
53 | LOGGER.debug("Downloading to '{}' with {}ms connection and {}ms download timeout...",
54 | config.getDownloadTarget(),
55 | config.getDownloadConnectionTimeoutInMillis(),
56 | config.getDownloadReadTimeoutInMillis());
57 |
58 | try {
59 | stopWatch.start();
60 | FileUtils.copyUrlToFile(
61 | config.getDownloadSource(),
62 | config.getDownloadTarget(),
63 | (int) config.getDownloadConnectionTimeoutInMillis(),
64 | (int) config.getDownloadReadTimeoutInMillis(),
65 | config.getDownloadProxy());
66 | stopWatch.stop();
67 | LOGGER.info("Download finished in {}ms", stopWatch.getTime());
68 | } catch (IOException e) {
69 | throw new DownloadException(
70 | "Could not download '" + config.getDownloadSource() + "' to '" + config.getDownloadTarget() + "'", e);
71 | } finally {
72 | notifyListeners();
73 | }
74 | }
75 |
76 | private void notifyListeners() {
77 | for (DownloadListener downloadListener : downloadListeners) {
78 | downloadListener.downloadFinished();
79 | }
80 | }
81 |
82 | }
83 |
84 | private interface DownloadListener {
85 | void downloadFinished();
86 | }
87 |
88 | private static class DownloadProgressNotifier implements Runnable, DownloadListener {
89 |
90 | private final Semaphore semaphore;
91 | private final EmbeddedRabbitMqConfig config;
92 |
93 | DownloadProgressNotifier(EmbeddedRabbitMqConfig config) {
94 | this.semaphore = new Semaphore(1);
95 | this.config = config;
96 | }
97 |
98 | @Override
99 | public void downloadFinished() {
100 | semaphore.release();
101 | }
102 |
103 | @Override
104 | public void run() {
105 | try {
106 | semaphore.acquire();
107 | } catch (InterruptedException e) {
108 | throw new IllegalStateException("Acquire should work!");
109 | }
110 | while (!semaphore.tryAcquire()) {
111 | try {
112 | LOGGER.debug("Downloaded {} bytes", config.getDownloadTarget().length());
113 | Thread.sleep(500);
114 | } catch (InterruptedException e) {
115 | LOGGER.trace("Download indicator interrupted");
116 | }
117 | }
118 | LOGGER.trace("Download indicator finished normally");
119 | }
120 | }
121 |
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/download/CachedDownloader.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.download;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import java.io.File;
9 |
10 | class CachedDownloader extends Downloader.Decorator {
11 |
12 | private static final Logger LOGGER = LoggerFactory.getLogger(CachedDownloader.class);
13 |
14 | private final EmbeddedRabbitMqConfig config;
15 |
16 | CachedDownloader(Downloader downloader, EmbeddedRabbitMqConfig config) {
17 | super(downloader);
18 | this.config = config;
19 | }
20 |
21 | @Override
22 | public void run() {
23 | if (isDownloadAlreadyCached()) {
24 | LOGGER.debug("RabbitMQ has been downloaded before. Using file: {}", config.getDownloadTarget());
25 | } else {
26 | download();
27 | }
28 | }
29 |
30 | private boolean isDownloadAlreadyCached() {
31 | File downloadTarget = config.getDownloadTarget();
32 | return downloadTarget.exists() && downloadTarget.isFile() && downloadTarget.canRead() && downloadTarget.length() > 0;
33 | }
34 |
35 | private void download() {
36 | try {
37 | innerDownloader.run();
38 | } catch (DownloadException e) {
39 | if (config.shouldDeleteCachedFileOnErrors()) {
40 | if (config.getDownloadTarget().exists()) {
41 | boolean deleted = config.getDownloadTarget().delete();
42 | if (deleted) {
43 | LOGGER.info("Removed partially downloaded file: {}", config.getDownloadTarget());
44 | } else {
45 | LOGGER.warn("Could not remove partially downloaded file. Please remove it manually: {}", config.getDownloadTarget());
46 | }
47 | }
48 | } else {
49 | LOGGER.info("Partially downloaded file will not be deleted: {}", config.getDownloadTarget());
50 | }
51 | throw e;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/download/DownloadException.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.download;
2 |
3 | public class DownloadException extends RuntimeException {
4 |
5 | public DownloadException(String msg) {
6 | super(msg);
7 | }
8 |
9 | public DownloadException(String msg, Throwable cause) {
10 | super(msg, cause);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/download/Downloader.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.download;
2 |
3 | public interface Downloader extends Runnable {
4 |
5 | @Override
6 | void run() throws DownloadException;
7 |
8 | abstract class Decorator implements Downloader {
9 |
10 | final Downloader innerDownloader;
11 |
12 | public Decorator(Downloader innerDownloader) {
13 | this.innerDownloader = innerDownloader;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/download/DownloaderFactory.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.download;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | public class DownloaderFactory {
6 |
7 | EmbeddedRabbitMqConfig config;
8 |
9 | public DownloaderFactory(EmbeddedRabbitMqConfig config) {
10 | this.config = config;
11 | }
12 |
13 | /**
14 | * @return an appropriate instance depending on the given configuration.
15 | */
16 | public Downloader getNewInstance() {
17 | Downloader downloader = new BasicDownloader(config);
18 | if (config.shouldCachedDownload()) {
19 | downloader = new CachedDownloader(downloader, config);
20 | }
21 | return downloader;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/extract/BasicExtractor.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.extract;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 | import io.arivera.oss.embedded.rabbitmq.apache.commons.lang3.StopWatch;
5 | import io.arivera.oss.embedded.rabbitmq.util.ArchiveType;
6 |
7 | import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
8 | import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
9 | import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
10 | import org.apache.commons.compress.archivers.zip.ZipFile;
11 | import org.apache.commons.compress.utils.IOUtils;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import org.tukaani.xz.XZInputStream;
15 |
16 | import java.io.BufferedInputStream;
17 | import java.io.BufferedOutputStream;
18 | import java.io.File;
19 | import java.io.FileInputStream;
20 | import java.io.FileOutputStream;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.nio.file.Files;
24 | import java.nio.file.Path;
25 | import java.nio.file.Paths;
26 | import java.util.Enumeration;
27 | import java.util.zip.GZIPInputStream;
28 |
29 | class BasicExtractor implements Extractor {
30 |
31 | private static final Logger LOGGER = LoggerFactory.getLogger(BasicExtractor.class);
32 |
33 | private final EmbeddedRabbitMqConfig config;
34 |
35 | BasicExtractor(EmbeddedRabbitMqConfig config) {
36 | this.config = config;
37 | }
38 |
39 | @Override
40 | public void run() throws ExtractionException {
41 | Runnable extractor = getExtractor(config);
42 | extractor.run();
43 | }
44 |
45 | CompressedExtractor getExtractor(EmbeddedRabbitMqConfig config) {
46 | String downloadedFilename = config.getDownloadTarget().toString();
47 | if (ArchiveType.TAR_GZ.matches(downloadedFilename)) {
48 | return new TarGzExtractor(config);
49 | } else if (ArchiveType.TAR_XZ.matches(downloadedFilename)) {
50 | return new TarXzExtractor(config);
51 | } else if (ArchiveType.ZIP.matches(downloadedFilename)) {
52 | return new ZipExtractor(config);
53 | } else {
54 | throw new IllegalStateException("Could not determine compression format for file: " + downloadedFilename);
55 | }
56 | }
57 |
58 | abstract static class CompressedExtractor implements Runnable {
59 |
60 | protected final EmbeddedRabbitMqConfig config;
61 |
62 | CompressedExtractor(EmbeddedRabbitMqConfig config) {
63 | this.config = config;
64 | }
65 |
66 | protected static void createNewFile(File destPath) {
67 | try {
68 | boolean newFile = destPath.createNewFile();
69 | if (!newFile) {
70 | LOGGER.warn("File '{}' already exists. Will attempt to continue...", destPath);
71 | }
72 | } catch (IOException e) {
73 | LOGGER.warn("Could not extract file '" + destPath + "'. Will attempt to continue...", e);
74 | }
75 | }
76 |
77 | protected static void makeDirectory(File destPath) {
78 | boolean mkdirs = destPath.mkdirs();
79 | if (!mkdirs) {
80 | LOGGER.warn("Directory '{}' could not be created. Will attempt to continue...", destPath);
81 | }
82 | }
83 |
84 | protected static void extractFile(InputStream archive, File destPath, String fileName) {
85 | BufferedOutputStream output = null;
86 | try {
87 | LOGGER.debug("Extracting '{}'...", fileName);
88 | output = new BufferedOutputStream(new FileOutputStream(destPath));
89 | IOUtils.copy(archive, output);
90 | } catch (IOException e) {
91 | throw new ExtractionException("Error extracting file '" + fileName + "' ", e);
92 | } finally {
93 | IOUtils.closeQuietly(output);
94 | }
95 | }
96 |
97 | }
98 |
99 | abstract static class AbstractTarExtractor extends CompressedExtractor {
100 |
101 | AbstractTarExtractor(EmbeddedRabbitMqConfig config) {
102 | super(config);
103 | }
104 |
105 | @Override
106 | public void run() throws ExtractionException {
107 | String downloadedFile = config.getDownloadTarget().toString();
108 | TarArchiveInputStream archive;
109 | try {
110 | BufferedInputStream bufferedFileInput =
111 | new BufferedInputStream(new FileInputStream(config.getDownloadTarget()));
112 | InputStream compressedInputStream = getCompressedInputStream(downloadedFile, bufferedFileInput);
113 | archive = new TarArchiveInputStream(compressedInputStream);
114 | } catch (IOException e) {
115 | throw new ExtractionException(
116 | "Download file '" + config.getDownloadTarget() + "' was not found or is not accessible.", e);
117 | }
118 |
119 | try {
120 | LOGGER.info("Extracting '{}' to '{}'", config.getDownloadTarget(), config.getExtractionFolder());
121 | StopWatch stopWatch = new StopWatch();
122 | stopWatch.start();
123 | extractTar(archive);
124 | stopWatch.stop();
125 | LOGGER.info("Finished extracting files in {}ms", stopWatch.getTime());
126 | } finally {
127 | IOUtils.closeQuietly(archive);
128 | }
129 | }
130 |
131 | protected abstract InputStream getCompressedInputStream(String downloadedFile,
132 | BufferedInputStream bufferedFileInput) throws IOException;
133 |
134 | private void extractTar(TarArchiveInputStream archive) {
135 | TarArchiveEntry fileToExtract;
136 | try {
137 | fileToExtract = archive.getNextTarEntry();
138 | } catch (IOException e) {
139 | throw new ExtractionException("Could not extract files from file '" + config.getDownloadTarget()
140 | + "' due to: " + e.getLocalizedMessage(), e);
141 | }
142 |
143 | while (fileToExtract != null) {
144 | File destPath = new File(config.getExtractionFolder(), fileToExtract.getName());
145 |
146 | if (fileToExtract.isDirectory()) {
147 | makeDirectory(destPath);
148 | } else if (fileToExtract.isLink()) {
149 | createLink(fileToExtract, destPath);
150 | } else {
151 | createNewFile(destPath);
152 |
153 | int mode = fileToExtract.getMode(); // example: 764
154 | int ownerBits = mode >> 2; // owner bits: 7
155 | int isExecutable = ownerBits & 1; // bits: RWX, where X = executable bit
156 | boolean madeExecutable = destPath.setExecutable(isExecutable == 1);
157 | if (!madeExecutable) {
158 | LOGGER.warn("File '{}' (original mode {}) could not be made executable probably due to permission issues.",
159 | fileToExtract.getName(), mode);
160 | }
161 |
162 | boolean madeReadable = destPath.setReadable(true);
163 | if (!madeReadable) {
164 | LOGGER.warn("File '{}' (original mode {}) could not be made readable probably due to permission issues.",
165 | fileToExtract.getName(), mode);
166 | }
167 |
168 | extractFile(archive, destPath, fileToExtract.getName());
169 | }
170 |
171 | try {
172 | fileToExtract = archive.getNextTarEntry();
173 | } catch (IOException e) {
174 | LOGGER.error("Could not find next file to extract.", e);
175 | break;
176 | }
177 | }
178 |
179 | File extractionFolder = config.getExtractionFolder();
180 | boolean madeReadable = extractionFolder.setReadable(true);
181 | if (!madeReadable) {
182 | LOGGER.warn("File '{}' could not be made readable probably due to permission issues.",
183 | extractionFolder);
184 | }
185 |
186 | }
187 |
188 | private void createLink(TarArchiveEntry fileToExtract, File destPath) {
189 | Path link = Paths.get(destPath.toURI());
190 | Path existingFile = Paths.get(config.getExtractionFolder().toString(), fileToExtract.getLinkName());
191 | try {
192 | LOGGER.debug("Extracting '{}'...", destPath);
193 | Files.createLink(link, existingFile);
194 | } catch (IOException e) {
195 | LOGGER.warn("Could not create link '{}' to '{}'", link, existingFile, e);
196 | }
197 | }
198 |
199 | }
200 |
201 | private static class TarGzExtractor extends AbstractTarExtractor {
202 |
203 | public TarGzExtractor(EmbeddedRabbitMqConfig config) {
204 | super(config);
205 | }
206 |
207 | @Override
208 | protected InputStream getCompressedInputStream(String downloadedFile,
209 | BufferedInputStream bufferedFileInput)
210 | throws IOException {
211 | return new GZIPInputStream(bufferedFileInput);
212 | }
213 | }
214 |
215 | private static class TarXzExtractor extends AbstractTarExtractor {
216 |
217 | public TarXzExtractor(EmbeddedRabbitMqConfig config) {
218 | super(config);
219 | }
220 |
221 | protected InputStream getCompressedInputStream(String downloadedFile,
222 | BufferedInputStream bufferedFileInput) throws IOException {
223 | return new XZInputStream(bufferedFileInput);
224 | }
225 | }
226 |
227 | private static class ZipExtractor extends CompressedExtractor {
228 |
229 | public ZipExtractor(EmbeddedRabbitMqConfig config) {
230 | super(config);
231 | }
232 |
233 | @Override
234 | public void run() throws ExtractionException {
235 | ZipFile zipFile;
236 | try {
237 | zipFile = new ZipFile(config.getDownloadTarget());
238 | } catch (IOException e) {
239 | throw new ExtractionException(
240 | "Download file '" + config.getDownloadTarget() + "' was not found or is not accessible.", e);
241 | }
242 |
243 | try {
244 | LOGGER.info("Extracting '{}' to '{}'", config.getDownloadTarget(), config.getExtractionFolder());
245 | StopWatch stopWatch = new StopWatch();
246 | stopWatch.start();
247 | extractZip(zipFile);
248 | stopWatch.stop();
249 | LOGGER.info("Finished extracting files in {}ms", stopWatch.getTime());
250 | } finally {
251 | IOUtils.closeQuietly(zipFile);
252 | }
253 | }
254 |
255 | private void extractZip(ZipFile zipFile) {
256 | Enumeration entries = zipFile.getEntries();
257 | while (entries.hasMoreElements()) {
258 |
259 | ZipArchiveEntry entry = entries.nextElement();
260 | String fileName = entry.getName();
261 | File outputFile = new File(config.getExtractionFolder(), fileName);
262 |
263 | if (entry.isDirectory()) {
264 | makeDirectory(outputFile);
265 | } else {
266 | createNewFile(outputFile);
267 | try {
268 | InputStream inputStream = zipFile.getInputStream(entry);
269 | extractFile(inputStream, outputFile, fileName);
270 | } catch (IOException e) {
271 | throw new ExtractionException("Error extracting file '" + fileName + "' "
272 | + "from downloaded file: " + config.getDownloadTarget(), e);
273 | }
274 | }
275 | }
276 | }
277 | }
278 |
279 | }
280 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/extract/CachedExtractor.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.extract;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | class CachedExtractor extends Extractor.Decorator {
9 |
10 | private static final Logger LOGGER = LoggerFactory.getLogger(CachedExtractor.class);
11 |
12 | private final EmbeddedRabbitMqConfig config;
13 |
14 | CachedExtractor(Extractor extractor, EmbeddedRabbitMqConfig config) {
15 | super(extractor);
16 | this.config = config;
17 | }
18 |
19 | @Override
20 | public void run() throws ExtractionException {
21 | try {
22 | innerExtractor.run();
23 | } catch (ExtractionException e) {
24 | if (config.shouldDeleteCachedFileOnErrors()) {
25 | boolean deleted = config.getDownloadTarget().delete();
26 | if (deleted) {
27 | LOGGER.info("Removed downloaded file because it's possibly corrupted: {}", config.getDownloadTarget());
28 | } else {
29 | LOGGER.warn("Could not delete downloaded file. Please remove it manually: {}", config.getDownloadTarget());
30 | }
31 | } else {
32 | LOGGER.info("Downloaded file is possibly corrupted but won't be removed: {}", config.getDownloadTarget());
33 | }
34 | throw e;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/extract/ExtractionException.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.extract;
2 |
3 | public class ExtractionException extends RuntimeException {
4 |
5 | public ExtractionException(String message) {
6 | super(message);
7 | }
8 |
9 | public ExtractionException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/extract/Extractor.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.extract;
2 |
3 | public interface Extractor extends Runnable {
4 |
5 | @Override
6 | void run() throws ExtractionException;
7 |
8 | abstract class Decorator implements Extractor {
9 |
10 | protected final Extractor innerExtractor;
11 |
12 | public Decorator(Extractor innerExtractor) {
13 | this.innerExtractor = innerExtractor;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/extract/ExtractorFactory.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.extract;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | public class ExtractorFactory {
6 |
7 | private EmbeddedRabbitMqConfig config;
8 |
9 | public ExtractorFactory(EmbeddedRabbitMqConfig config) {
10 | this.config = config;
11 | }
12 |
13 | /**
14 | * Returns an Extractor instance appropriate based on the given configuration.
15 | */
16 | public Extractor getNewInstance() {
17 | Extractor extractor = new BasicExtractor(config);
18 | if (config.shouldCachedDownload()) {
19 | extractor = new CachedExtractor(extractor, config);
20 | }
21 | return extractor;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/helpers/ErlangVersionChecker.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.helpers;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 | import io.arivera.oss.embedded.rabbitmq.bin.ErlangShell;
5 | import io.arivera.oss.embedded.rabbitmq.bin.ErlangShellException;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.util.Locale;
11 |
12 | /**
13 | * A class that helps enforce the existence and version requirements of Erlang to run RabbitMQ.
14 | */
15 | public class ErlangVersionChecker {
16 |
17 | private static final Logger LOGGER = LoggerFactory.getLogger(ErlangVersionChecker.class);
18 |
19 | private final ErlangShell erlangShell;
20 | private final String minErlangVersion;
21 |
22 | public ErlangVersionChecker(EmbeddedRabbitMqConfig config) {
23 | this(config.getVersion().getMinimumErlangVersion(), new ErlangShell(config));
24 | }
25 |
26 | public ErlangVersionChecker(String minErlangVersion, ErlangShell erlangShell) {
27 | this.minErlangVersion = minErlangVersion;
28 | this.erlangShell = erlangShell;
29 | }
30 |
31 | /**
32 | * Retrieves the current system's Erlang version to compare it to the minimum required version.
33 | *
34 | * The system's Erlang version is always retrieved, but the comparison might be skipped if the RabbitMQ version
35 | * doesn't specify a minimum required version.
36 | *
37 | * @throws ErlangVersionException if the minimum required version is not met or if it can't be determined.
38 | */
39 | public void check() throws ErlangVersionException {
40 | String erlangVersion;
41 | try {
42 | erlangVersion = erlangShell.getErlangVersion();
43 | LOGGER.debug("Erlang version installed in this system: {}", erlangVersion);
44 | } catch (ErlangShellException e) {
45 | throw new ErlangVersionException("Could not determine Erlang version. Ensure Erlang is correctly installed.", e);
46 | }
47 |
48 | if (minErlangVersion == null) {
49 | LOGGER.debug("RabbitMQ version to execute doesn't specify a minimum Erlang version. Will skip this check.");
50 | return;
51 | } else {
52 | LOGGER.debug("RabbitMQ version to execute requires Erlang version {} or above.", minErlangVersion);
53 | }
54 |
55 | int[] expected;
56 | int[] actual;
57 | try {
58 | expected = parse(minErlangVersion);
59 | actual = parse(erlangVersion);
60 | } catch (RuntimeException e) {
61 | LOGGER.warn("Error parsing Erlang version: " + minErlangVersion + " or " + erlangVersion + ". Ignoring check...");
62 | return;
63 | }
64 |
65 | for (int i = 0; i < actual.length; i++) {
66 | if (actual[i] > expected[i]) {
67 | break;
68 | }
69 | if (actual[i] < expected[i]) {
70 | throw new ErlangVersionException(
71 | String.format("Minimum required Erlang version not found. Expected '%s' or higher. Actual is: '%s'",
72 | minErlangVersion, erlangVersion));
73 | }
74 | }
75 | }
76 |
77 | /**
78 | * @return a numeric value useful for comparing versions.
79 | */
80 | static int[] parse(String erlangVersion) {
81 | int[] version = {0, 0, 0, 0, 0};
82 | if (erlangVersion.startsWith("r") || erlangVersion.startsWith("R") ) {
83 | erlangVersion = erlangVersion.substring(1); // "R15B03-1" -> "15B03-1"
84 | String[] components = erlangVersion.split("\\D", 2); // "15B03-1" -> ["15", "03-1"]
85 | version[0] = Integer.parseInt(components[0]); // "15" -> 15
86 | version[1] = erlangVersion.toUpperCase(Locale.US)
87 | .replaceAll("[^A-Z]", "").charAt(0); // "15B03-1-" -> "B" -> 66
88 | if (components.length >= 2
89 | && !components[1].isEmpty()
90 | && components[1].indexOf("-") != 0) {
91 | version[2] = Integer.parseInt(components[1].split("-", 2)[0]); // "03-1" -> "03" -> 3
92 | }
93 | } else {
94 | String[] components = erlangVersion.split("\\.", 5);
95 | for (int i = 0; i < components.length; i++) {
96 | version[i] = Integer.parseInt(components[i]);
97 | }
98 | }
99 | return version;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/helpers/ErlangVersionException.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.helpers;
2 |
3 | public class ErlangVersionException extends RuntimeException {
4 |
5 | public ErlangVersionException(String message) {
6 | super(message);
7 | }
8 |
9 | public ErlangVersionException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/helpers/ShutDownException.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.helpers;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.bin.RabbitMqCommandException;
4 |
5 | public class ShutDownException extends RabbitMqCommandException {
6 |
7 | public ShutDownException(String msg, Throwable cause) {
8 | super(msg, cause);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/helpers/ShutdownHelper.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.helpers;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 | import io.arivera.oss.embedded.rabbitmq.bin.RabbitMqCommandException;
5 | import io.arivera.oss.embedded.rabbitmq.bin.RabbitMqCtl;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.zeroturnaround.exec.ProcessResult;
10 |
11 | import java.util.concurrent.ExecutionException;
12 | import java.util.concurrent.Future;
13 | import java.util.concurrent.TimeUnit;
14 | import java.util.concurrent.TimeoutException;
15 |
16 | /**
17 | * A helper class used to shut down a specific RabbitMQ Process and wait until it's the process is stopped.
18 | */
19 | public class ShutdownHelper implements Runnable {
20 |
21 | private static final Logger LOGGER = LoggerFactory.getLogger(ShutdownHelper.class);
22 |
23 | private final EmbeddedRabbitMqConfig config;
24 | private final Future rabbitMqProcess;
25 | private final long timeoutDuration;
26 | private final TimeUnit timeoutUnit;
27 |
28 | /**
29 | * Constructs a new instance that will be used to shut down the given RabbitMQ server process.
30 | */
31 | public ShutdownHelper(EmbeddedRabbitMqConfig config, Future rabbitMqProcess) {
32 | this.config = config;
33 | this.rabbitMqProcess = rabbitMqProcess;
34 | this.timeoutDuration = config.getDefaultRabbitMqCtlTimeoutInMillis();
35 | this.timeoutUnit = TimeUnit.MILLISECONDS;
36 | }
37 |
38 | @Override
39 | public void run() throws ShutDownException {
40 | submitShutdownRequest();
41 | confirmShutdown();
42 | }
43 |
44 | private void submitShutdownRequest() throws ShutDownException {
45 | Future resultFuture;
46 | try {
47 | resultFuture = new RabbitMqCtl(config).stop();
48 | } catch (RabbitMqCommandException e) {
49 | throw new ShutDownException("Could not successfully execute command to stop RabbitMQ Server", e);
50 | }
51 |
52 | int exitValue;
53 | try {
54 | ProcessResult rabbitMqCtlProcessResult = resultFuture.get(timeoutDuration, timeoutUnit);
55 | exitValue = rabbitMqCtlProcessResult.getExitValue();
56 | } catch (InterruptedException | ExecutionException | TimeoutException e) {
57 | throw new ShutDownException("Error while waiting " + timeoutDuration + " " + timeoutUnit + " for command "
58 | + "to shut down RabbitMQ Server to finish", e);
59 | }
60 |
61 | if (exitValue == 0) {
62 | LOGGER.debug("Successfully commanded RabbitMQ Server to stop.");
63 | } else {
64 | LOGGER.warn("Command to stop RabbitMQ Sever failed with exit value: " + exitValue);
65 | }
66 | }
67 |
68 | private void confirmShutdown() throws ShutDownException {
69 | int exitValue;
70 | try {
71 | ProcessResult rabbitMqProcessResult = rabbitMqProcess.get(timeoutDuration, TimeUnit.MILLISECONDS);
72 | exitValue = rabbitMqProcessResult.getExitValue();
73 | } catch (InterruptedException | ExecutionException | TimeoutException e) {
74 | throw new ShutDownException("Error while waiting " + timeoutDuration + " " + timeoutUnit + "for "
75 | + "RabbitMQ Server to shut down", e);
76 | }
77 |
78 | if (exitValue == 0) {
79 | LOGGER.debug("RabbitMQ Server stopped successfully.");
80 | } else {
81 | LOGGER.warn("RabbitMQ Server stopped with exit value: " + exitValue);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/helpers/StartupException.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.helpers;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.bin.RabbitMqCommandException;
4 |
5 | public class StartupException extends RabbitMqCommandException {
6 |
7 | public StartupException(String msg) {
8 | super(msg);
9 | }
10 |
11 | public StartupException(String msg, Throwable cause) {
12 | super(msg, cause);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/helpers/StartupHelper.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.helpers;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 | import io.arivera.oss.embedded.rabbitmq.bin.RabbitMqCommand;
5 | import io.arivera.oss.embedded.rabbitmq.bin.RabbitMqCommandException;
6 | import io.arivera.oss.embedded.rabbitmq.bin.RabbitMqServer;
7 |
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.zeroturnaround.exec.ProcessResult;
11 | import org.zeroturnaround.exec.listener.ProcessListener;
12 | import org.zeroturnaround.exec.stream.LogOutputStream;
13 |
14 | import java.util.ArrayList;
15 | import java.util.Arrays;
16 | import java.util.List;
17 | import java.util.concurrent.Callable;
18 | import java.util.concurrent.Future;
19 | import java.util.concurrent.Semaphore;
20 | import java.util.concurrent.TimeUnit;
21 | import java.util.regex.Pattern;
22 |
23 | public class StartupHelper implements Callable> {
24 |
25 | public static final String BROKER_STARTUP_COMPLETED = ".*completed with \\d+ plugins.*";
26 | private final EmbeddedRabbitMqConfig config;
27 |
28 | public StartupHelper(EmbeddedRabbitMqConfig config) {
29 | this.config = config;
30 | }
31 |
32 | /**
33 | * Starts the RabbitMQ Server and blocks the current thread until the server is confirmed to have started.
34 | *
35 | * This is useful to ensure no other interactions happen with the RabbitMQ Server until it's safe to do so
36 | *
37 | * @return an unfinished future representing the eventual result of the {@code rabbitmq-server} process running in "foreground".
38 | * @throws StartupException if anything fails while attempting to start and confirm successful initialization.
39 | * @see ShutdownHelper
40 | */
41 | @Override
42 | public Future call() throws StartupException {
43 | PatternFinderOutputStream initializationWatcher = new PatternFinderOutputStream(BROKER_STARTUP_COMPLETED);
44 |
45 | // Inform the initializationWatcher if the process ends before the expected output is produced.
46 | PublishingProcessListener rabbitMqProcessListener = new PublishingProcessListener();
47 | rabbitMqProcessListener.addSubscriber(initializationWatcher);
48 |
49 | Future resultFuture = startProcess(initializationWatcher, rabbitMqProcessListener);
50 | waitForConfirmation(initializationWatcher);
51 |
52 | return resultFuture;
53 | }
54 |
55 | private Future startProcess(PatternFinderOutputStream initializationWatcher,
56 | PublishingProcessListener rabbitMqProcessListener) {
57 | Future resultFuture;
58 | try {
59 | resultFuture = new RabbitMqServer(config)
60 | .writeOutputTo(initializationWatcher)
61 | .listeningToEventsWith(rabbitMqProcessListener)
62 | .start();
63 | } catch (RabbitMqCommandException e) {
64 | throw new StartupException("Could not start RabbitMQ Server", e);
65 | }
66 | return resultFuture;
67 | }
68 |
69 | private void waitForConfirmation(PatternFinderOutputStream initializationWatcher) {
70 | long timeout = config.getRabbitMqServerInitializationTimeoutInMillis();
71 | boolean match = initializationWatcher.waitForMatch(timeout, TimeUnit.MILLISECONDS);
72 |
73 | if (!match) {
74 | throw new StartupException(
75 | "Could not confirm RabbitMQ Server initialization completed successfully within " + timeout + "ms");
76 | }
77 | }
78 |
79 | /**
80 | * Notifies subscribers of process termination so they don't have to rely on blocking {@link Future#get()} of
81 | * {@link ProcessResult}s, which is returned by {@link RabbitMqCommand}s.
82 | */
83 | static class PublishingProcessListener extends ProcessListener {
84 |
85 | interface Subscriber {
86 | void processFinished(int exitValue);
87 | }
88 |
89 | private final List subscribers;
90 |
91 | public PublishingProcessListener(Subscriber... subscribers) {
92 | this.subscribers = new ArrayList<>(Arrays.asList(subscribers));
93 | }
94 |
95 | @Override
96 | public void afterFinish(Process process, ProcessResult result) {
97 | super.afterFinish(process, result);
98 | for (Subscriber subscriber : subscribers) {
99 | subscriber.processFinished(result.getExitValue());
100 | }
101 | }
102 |
103 | public void addSubscriber(Subscriber subscriber) {
104 | this.subscribers.add(subscriber);
105 | }
106 |
107 | }
108 |
109 | /**
110 | * An output stream that compares each line with a given pattern.
111 | *
112 | * This class offers the ability to wait until the pattern is found or the given amount of time has passed.
113 | */
114 | static class PatternFinderOutputStream extends LogOutputStream implements PublishingProcessListener.Subscriber {
115 |
116 | private static final Logger LOGGER = LoggerFactory.getLogger(PatternFinderOutputStream.class);
117 |
118 | private final Pattern pattern;
119 | private final Semaphore lock;
120 | private boolean matchFound;
121 |
122 | public PatternFinderOutputStream(String initializationMarkerPattern) {
123 | this(Pattern.compile(initializationMarkerPattern, Pattern.CASE_INSENSITIVE));
124 | }
125 |
126 | public PatternFinderOutputStream(Pattern initializationMarkerPattern) {
127 | try {
128 | lock = new Semaphore(1);
129 | lock.acquire();
130 | } catch (InterruptedException e) {
131 | throw new IllegalStateException("Could not acquire a lock we create right above?", e);
132 | }
133 | pattern = initializationMarkerPattern;
134 | matchFound = false;
135 | }
136 |
137 | @Override
138 | protected void processLine(String line) {
139 | if (pattern.matcher(line).matches()) {
140 | LOGGER.trace("Pattern '{}' found in line: {}", pattern, line);
141 | matchFound = true;
142 | lock.release();
143 | }
144 | LOGGER.trace("Pattern '{}' NOT found in line: {}", pattern, line);
145 | }
146 |
147 | @Override
148 | public void processFinished(int exitValue) {
149 | LOGGER.debug("No more output is expected since process finished (exit code: {})", exitValue);
150 | lock.release();
151 | }
152 |
153 | public boolean waitForMatch(long duration, TimeUnit timeUnit) {
154 | try {
155 | boolean acquired = lock.tryAcquire(duration, timeUnit);
156 | if (!acquired) {
157 | LOGGER.info("Waited for {} {} for pattern '{}' to appear but it didn't.", duration, timeUnit, pattern );
158 | }
159 | } catch (InterruptedException e) {
160 | LOGGER.warn("Error while waiting for process output that matches the pattern '{}'", pattern);
161 | }
162 | return isMatchFound();
163 | }
164 |
165 | public boolean isMatchFound() {
166 | return matchFound;
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/util/ArchiveType.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.util;
2 |
3 | import java.util.Locale;
4 |
5 | public enum ArchiveType {
6 |
7 | TAR_GZ, TAR_XZ, ZIP;
8 |
9 | public String getExtension() {
10 | return name().toLowerCase(Locale.US).replace("_", ".");
11 | }
12 |
13 | public boolean matches(String filesname) {
14 | return filesname.endsWith(getExtension());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/util/OperatingSystem.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.util;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.apache.commons.lang3.SystemUtils;
4 |
5 | public enum OperatingSystem {
6 |
7 | WINDOWS, MAC_OS, UNIX;
8 |
9 | /**
10 | * Returns the right instance of the Operation System.
11 | *
12 | * @see SystemUtils#IS_OS_MAC
13 | * @see SystemUtils#IS_OS_WINDOWS
14 | */
15 | public static OperatingSystem detect() {
16 | if (SystemUtils.IS_OS_MAC) {
17 | return MAC_OS;
18 | } else if (SystemUtils.IS_OS_WINDOWS) {
19 | return WINDOWS;
20 | } else {
21 | return UNIX;
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/util/RandomPortSupplier.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.IOException;
7 | import java.net.ServerSocket;
8 | import javax.net.ServerSocketFactory;
9 |
10 | public class RandomPortSupplier {
11 |
12 | private static final Logger LOGGER = LoggerFactory.getLogger(RandomPortSupplier.class);
13 |
14 | private final ServerSocketFactory severSocketFactory;
15 |
16 | public RandomPortSupplier() {
17 | this(ServerSocketFactory.getDefault());
18 | }
19 |
20 | public RandomPortSupplier(ServerSocketFactory severSocketFactory) {
21 | this.severSocketFactory = severSocketFactory;
22 | }
23 |
24 | /**
25 | * @return an available port assigned at random by the OS.
26 | *
27 | * @throws IllegalStateException if the port cannot be determined.
28 | */
29 | public int get() throws IllegalStateException {
30 | ServerSocket socket = null;
31 | try {
32 | socket = this.severSocketFactory.createServerSocket(0);
33 | socket.setReuseAddress(false);
34 | return socket.getLocalPort();
35 | } catch (IOException e) {
36 | throw new IllegalStateException("Could not determine random port to assign.", e);
37 | } finally {
38 | if (socket != null) {
39 | try {
40 | socket.close();
41 | } catch (IOException e) {
42 | LOGGER.debug("Couldn't close socket that was temporarily opened to determine random port.", e);
43 | }
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/io/arivera/oss/embedded/rabbitmq/util/StringUtils.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.util;
2 |
3 | import java.util.Collection;
4 |
5 | public class StringUtils {
6 |
7 | /**
8 | * Joins the elements of the provided collection into a single String containing the provided list of elements.
9 | *
10 | * No delimiter is added before or after the list.
11 | *
12 | * Empty collections return an empty String.
13 | */
14 | public static String join(Collection collection, CharSequence joinedBy) {
15 | if (collection.isEmpty()) {
16 | return "";
17 | }
18 | StringBuilder stringBuilder = new StringBuilder(256);
19 | for (T t : collection) {
20 | stringBuilder.append(t.toString()).append(joinedBy);
21 | }
22 | return stringBuilder.substring(0, stringBuilder.length() - joinedBy.length());
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/test/java/com/sample/project/EmbeddedRabbitMqTest.java:
--------------------------------------------------------------------------------
1 | package com.sample.project;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMq;
4 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
5 | import io.arivera.oss.embedded.rabbitmq.OfficialArtifactRepository;
6 | import io.arivera.oss.embedded.rabbitmq.PredefinedVersion;
7 | import io.arivera.oss.embedded.rabbitmq.RabbitMqEnvVar;
8 | import io.arivera.oss.embedded.rabbitmq.bin.RabbitMqCtl;
9 | import io.arivera.oss.embedded.rabbitmq.bin.RabbitMqPlugins;
10 | import io.arivera.oss.embedded.rabbitmq.bin.plugins.Plugin;
11 |
12 | import com.rabbitmq.client.Channel;
13 | import com.rabbitmq.client.Connection;
14 | import com.rabbitmq.client.ConnectionFactory;
15 | import org.junit.After;
16 | import org.junit.Rule;
17 | import org.junit.Test;
18 | import org.junit.rules.TemporaryFolder;
19 | import org.slf4j.LoggerFactory;
20 | import org.zeroturnaround.exec.ProcessResult;
21 |
22 | import java.io.File;
23 | import java.io.PrintWriter;
24 | import java.net.HttpURLConnection;
25 | import java.net.URL;
26 | import java.util.Collections;
27 | import java.util.Map;
28 | import java.util.Set;
29 | import java.util.concurrent.TimeUnit;
30 |
31 | import static org.hamcrest.CoreMatchers.containsString;
32 | import static org.hamcrest.CoreMatchers.equalTo;
33 | import static org.hamcrest.CoreMatchers.hasItems;
34 | import static org.hamcrest.CoreMatchers.notNullValue;
35 | import static org.hamcrest.MatcherAssert.assertThat;
36 | import static org.hamcrest.core.Is.is;
37 |
38 | public class EmbeddedRabbitMqTest {
39 |
40 | private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(EmbeddedRabbitMqTest.class);
41 |
42 | @Rule
43 | public TemporaryFolder temporaryFolder = new TemporaryFolder();
44 | private EmbeddedRabbitMq rabbitMq;
45 |
46 | @Test
47 | public void start() throws Exception {
48 | java.lang.System.setProperty("https.protocols", "TLSv1.2");
49 |
50 | File configFile = temporaryFolder.newFile("rabbitmq.conf");
51 | PrintWriter writer = new PrintWriter(configFile, "UTF-8");
52 | writer.println("log.connection.level = debug");
53 | writer.println("log.channel.level = debug");
54 | writer.close();
55 |
56 | EmbeddedRabbitMqConfig config = new EmbeddedRabbitMqConfig.Builder()
57 | .version(PredefinedVersion.LATEST)
58 | // .version(new BaseVersion("3.8.1"))
59 | // .randomPort()
60 | .downloadFrom(OfficialArtifactRepository.GITHUB)
61 | // .downloadFrom(new URL("https://github.com/rabbitmq/rabbitmq-server/releases/download/rabbitmq_v3_6_6_milestone1/rabbitmq-server-mac-standalone-3.6.5.901.tar.xz"), "rabbitmq_server-3.6.5.901")
62 | // .envVar(RabbitMqEnvVar.NODE_PORT, String.valueOf(PORT))
63 | .envVar(RabbitMqEnvVar.CONFIG_FILE, configFile.toString().replace(".conf", ""))
64 | .extractionFolder(temporaryFolder.newFolder("extracted"))
65 | .rabbitMqServerInitializationTimeoutInMillis(TimeUnit.SECONDS.toMillis(20))
66 | .defaultRabbitMqCtlTimeoutInMillis(TimeUnit.SECONDS.toMillis(20))
67 | .erlangCheckTimeoutInMillis(TimeUnit.SECONDS.toMillis(10))
68 | // .useCachedDownload(false)
69 | .build();
70 |
71 | rabbitMq = new EmbeddedRabbitMq(config);
72 | rabbitMq.start();
73 | LOGGER.info("Back in the test!");
74 |
75 | ConnectionFactory connectionFactory = new ConnectionFactory();
76 | connectionFactory.setHost("localhost");
77 | connectionFactory.setPort(config.getRabbitMqPort());
78 | connectionFactory.setVirtualHost("/");
79 | connectionFactory.setUsername("guest");
80 | connectionFactory.setPassword("guest");
81 |
82 | Connection connection = connectionFactory.newConnection();
83 | assertThat(connection.isOpen(), equalTo(true));
84 | Channel channel = connection.createChannel();
85 | assertThat(channel.isOpen(), equalTo(true));
86 |
87 | ProcessResult listUsersResult = new RabbitMqCtl(config, Collections.singletonMap("TEST_ENV_VAR", "FooBar"))
88 | .execute("list_users")
89 | .get();
90 |
91 | assertThat(listUsersResult.getExitValue(), is(0));
92 | assertThat(listUsersResult.getOutput().getString(), containsString("guest"));
93 |
94 | RabbitMqPlugins rabbitMqPlugins = new RabbitMqPlugins(config);
95 | Map> groupedPlugins = rabbitMqPlugins.groupedList();
96 | assertThat(groupedPlugins.get(Plugin.State.ENABLED_EXPLICITLY).size(), equalTo(0));
97 |
98 | rabbitMqPlugins.enable("rabbitmq_management");
99 |
100 | Plugin plugin = rabbitMqPlugins.list().get("rabbitmq_management");
101 | assertThat(plugin, is(notNullValue()));
102 | assertThat(plugin.getState(),
103 | hasItems(Plugin.State.ENABLED_EXPLICITLY, Plugin.State.RUNNING));
104 |
105 | HttpURLConnection urlConnection = (HttpURLConnection) new URL("http://localhost:15672").openConnection();
106 | urlConnection.setRequestMethod("GET");
107 | urlConnection.connect();
108 |
109 | assertThat(urlConnection.getResponseCode(), equalTo(200));
110 | urlConnection.disconnect();
111 |
112 | rabbitMqPlugins.disable("rabbitmq_management");
113 |
114 | channel.close();
115 | connection.close();
116 | }
117 |
118 | @After
119 | public void tearDown() throws Exception {
120 | rabbitMq.stop();
121 | }
122 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/OfficialArtifactRepositoryTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.util.OperatingSystem;
4 |
5 | import org.junit.Test;
6 |
7 | import java.net.URL;
8 |
9 | import static org.hamcrest.CoreMatchers.equalTo;
10 | import static org.junit.Assert.assertNotNull;
11 | import static org.junit.Assert.assertThat;
12 |
13 | public class OfficialArtifactRepositoryTest {
14 |
15 | @Test
16 | public void downloadForWindows() throws Exception {
17 | URL url = OfficialArtifactRepository.RABBITMQ
18 | .getUrl(PredefinedVersion.V3_6_5, OperatingSystem.WINDOWS);
19 |
20 | assertThat(url.toString(),
21 | equalTo("http://www.rabbitmq.com/releases/rabbitmq-server"
22 | + "/v3.6.5/rabbitmq-server-windows-3.6.5.zip"));
23 | }
24 |
25 | @Test
26 | public void downloadForMac() throws Exception {
27 | URL url = OfficialArtifactRepository.RABBITMQ
28 | .getUrl(PredefinedVersion.V3_6_5, OperatingSystem.MAC_OS);
29 |
30 | assertThat(url.toString(),
31 | equalTo("http://www.rabbitmq.com/releases/rabbitmq-server"
32 | + "/v3.6.5/rabbitmq-server-mac-standalone-3.6.5.tar.xz"));
33 | }
34 |
35 | @Test
36 | public void downloadForUnix() throws Exception {
37 | URL url = OfficialArtifactRepository.RABBITMQ
38 | .getUrl(PredefinedVersion.V3_6_5, OperatingSystem.UNIX);
39 |
40 | assertThat(url.toString(),
41 | equalTo("http://www.rabbitmq.com/releases/rabbitmq-server"
42 | + "/v3.6.5/rabbitmq-server-generic-unix-3.6.5.tar.xz"));
43 | }
44 |
45 | @Test
46 | public void githubRepoOldForMac() throws Exception {
47 | URL url = OfficialArtifactRepository.GITHUB
48 | .getUrl(PredefinedVersion.V3_6_5, OperatingSystem.MAC_OS);
49 |
50 | assertThat(url.toString(),
51 | equalTo("https://github.com/rabbitmq/rabbitmq-server/releases/download"
52 | + "/rabbitmq_v3_6_5/rabbitmq-server-mac-standalone-3.6.5.tar.xz"));
53 | }
54 |
55 | @Test
56 | public void githubRepoNewForMac() throws Exception {
57 | URL url = OfficialArtifactRepository.GITHUB
58 | .getUrl(PredefinedVersion.V3_7_7, OperatingSystem.MAC_OS);
59 |
60 | assertThat(url.toString(),
61 | equalTo("https://github.com/rabbitmq/rabbitmq-server/releases/download"
62 | + "/v3.7.7/rabbitmq-server-mac-standalone-3.7.7.tar.xz"));
63 | }
64 |
65 | @Test
66 | public void githubRepoNewForMacAfterV3_7_18() throws Exception {
67 | URL url = OfficialArtifactRepository.GITHUB
68 | .getUrl(PredefinedVersion.V3_7_18, OperatingSystem.MAC_OS);
69 |
70 | assertThat(url.toString(),
71 | equalTo("https://github.com/rabbitmq/rabbitmq-server/releases/download"
72 | + "/v3.7.18/rabbitmq-server-generic-unix-3.7.18.tar.xz"));
73 |
74 | url = OfficialArtifactRepository.GITHUB
75 | .getUrl(PredefinedVersion.V3_8_0, OperatingSystem.MAC_OS);
76 |
77 | assertThat(url.toString(),
78 | equalTo("https://github.com/rabbitmq/rabbitmq-server/releases/download"
79 | + "/v3.8.0/rabbitmq-server-generic-unix-3.8.0.tar.xz"));
80 | }
81 |
82 | @Test
83 | public void githubRepoOldForUnix() throws Exception {
84 | URL url = OfficialArtifactRepository.GITHUB
85 | .getUrl(PredefinedVersion.V3_6_13, OperatingSystem.UNIX);
86 |
87 | assertThat(url.toString(),
88 | equalTo("https://github.com/rabbitmq/rabbitmq-server/releases/download"
89 | + "/rabbitmq_v3_6_13/rabbitmq-server-generic-unix-3.6.13.tar.xz"));
90 | }
91 |
92 | @Test
93 | public void githubRepoNewForUnix() throws Exception {
94 | URL url = OfficialArtifactRepository.GITHUB
95 | .getUrl(PredefinedVersion.V3_7_3, OperatingSystem.UNIX);
96 |
97 | assertThat(url.toString(),
98 | equalTo("https://github.com/rabbitmq/rabbitmq-server/releases/download"
99 | + "/v3.7.3/rabbitmq-server-generic-unix-3.7.3.tar.xz"));
100 | }
101 |
102 | @Test
103 | public void bintrayRepoNewForMac() throws Exception {
104 | URL url = OfficialArtifactRepository.BINTRAY
105 | .getUrl(PredefinedVersion.V3_7_7, OperatingSystem.MAC_OS);
106 |
107 | assertThat(url.toString(),
108 | equalTo("https://dl.bintray.com/rabbitmq/all/rabbitmq-server"
109 | + "/3.7.7/rabbitmq-server-mac-standalone-3.7.7.tar.xz"));
110 | }
111 |
112 | @Test(expected = IllegalStateException.class)
113 | public void rabbitMqRepoWontGenerateUrlForVersion3_7andHigher() throws Exception {
114 | OfficialArtifactRepository.RABBITMQ.getUrl(PredefinedVersion.V3_7_0, null);
115 | }
116 |
117 | @Test
118 | public void rabbitMqRepoWillGenerateUrlForVersionsBelow3_7() {
119 | URL url = OfficialArtifactRepository.RABBITMQ.getUrl(PredefinedVersion.V3_6_13, null);
120 | assertNotNull(url);
121 | }
122 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/PredefinedVersionTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.hamcrest.CoreMatchers.equalTo;
6 | import static org.junit.Assert.assertThat;
7 |
8 | public class PredefinedVersionTest {
9 |
10 | @Test
11 | public void version() throws Exception {
12 | assertThat(PredefinedVersion.V3_6_5.getVersionAsString(), equalTo("3.6.5"));
13 | assertThat(PredefinedVersion.V3_4_0.getVersionAsString(), equalTo("3.4.0"));
14 | }
15 |
16 | @Test
17 | public void latestEnumIsNewestVersion() throws Exception {
18 | PredefinedVersion firstDefinedEnumValue = PredefinedVersion.values()[0];
19 | assertThat(PredefinedVersion.LATEST.getVersionAsString(), equalTo(firstDefinedEnumValue.getVersionAsString()));
20 | }
21 |
22 | @Test
23 | public void testCompareTo() {
24 | assertThat(Version.VERSION_COMPARATOR.compare(PredefinedVersion.V3_7_5, PredefinedVersion.V3_7_5), equalTo(0));
25 | assertThat(Version.VERSION_COMPARATOR.compare(PredefinedVersion.V3_7_7, PredefinedVersion.V3_7_5), equalTo(1));
26 | assertThat(Version.VERSION_COMPARATOR.compare(PredefinedVersion.V3_6_13, PredefinedVersion.V3_7_7), equalTo(-1));
27 | }
28 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/bin/ErlangShellTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 | import io.arivera.oss.embedded.rabbitmq.PredefinedVersion;
5 |
6 | import org.junit.Before;
7 | import org.junit.Rule;
8 | import org.junit.Test;
9 | import org.junit.rules.TemporaryFolder;
10 | import org.junit.runner.RunWith;
11 | import org.mockito.runners.MockitoJUnitRunner;
12 |
13 | import java.util.HashMap;
14 | import java.util.concurrent.TimeUnit;
15 |
16 | import static org.hamcrest.MatcherAssert.assertThat;
17 | import static org.hamcrest.core.Is.is;
18 |
19 | @RunWith(MockitoJUnitRunner.class)
20 | public class ErlangShellTest {
21 | @Rule
22 | public TemporaryFolder tempFolder = new TemporaryFolder();
23 |
24 | private RabbitMqCommand.ProcessExecutorFactory factory = new RabbitMqCommand.ProcessExecutorFactory();
25 |
26 | private PredefinedVersion version = PredefinedVersion.LATEST;
27 | private EmbeddedRabbitMqConfig.Builder configBuilder;
28 |
29 | @Before
30 | public void setUp() throws Exception {
31 | configBuilder = new EmbeddedRabbitMqConfig.Builder()
32 | .envVars(new HashMap())
33 | .erlangCheckTimeoutInMillis(TimeUnit.SECONDS.toMillis(4))
34 | .extractionFolder(tempFolder.getRoot())
35 | .version(this.version)
36 | .processExecutorFactory(this.factory);
37 | }
38 |
39 | /**
40 | * This test can throw all sorts of noise and yet still succeed, because we don't *know* if you have Erlang installed!
41 | * @throws Exception If things go sideways
42 | */
43 | @Test
44 | public void checkForErlang() throws Exception {
45 | final ErlangShell shell = new ErlangShell(configBuilder.build());
46 | String erlangVersion = shell.getErlangVersion();
47 | assertThat(erlangVersion.isEmpty(), is(false));
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/bin/LoggingProcessListenerTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import org.apache.commons.lang3.RandomStringUtils;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.mockito.ArgumentCaptor;
8 | import org.mockito.Matchers;
9 | import org.mockito.Mock;
10 | import org.mockito.runners.MockitoJUnitRunner;
11 | import org.slf4j.Logger;
12 | import org.zeroturnaround.exec.ProcessExecutor;
13 | import org.zeroturnaround.exec.ProcessResult;
14 |
15 | import static org.hamcrest.CoreMatchers.containsString;
16 | import static org.junit.Assert.assertThat;
17 | import static org.mockito.Matchers.anyString;
18 | import static org.mockito.Mockito.never;
19 | import static org.mockito.Mockito.verify;
20 |
21 | @RunWith(MockitoJUnitRunner.class)
22 | public class LoggingProcessListenerTest {
23 |
24 | @Mock
25 | Logger logger;
26 | private ProcessExecutor processExecutor;
27 | private String command;
28 | private LoggingProcessListener loggingProcessListener;
29 |
30 | @Before
31 | public void setUp() throws Exception {
32 | command = RandomStringUtils.randomAlphabetic(5);
33 | processExecutor = new ProcessExecutor(command);
34 |
35 | loggingProcessListener = new LoggingProcessListener(logger);
36 | loggingProcessListener.beforeStart(processExecutor);
37 | }
38 |
39 | @Test
40 | public void logsCommandToExecute() throws Exception {
41 | ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(String.class);
42 | ArgumentCaptor commandCaptor = ArgumentCaptor.forClass(String.class);
43 | verify(logger).debug(msgCaptor.capture(), commandCaptor.capture(), anyString());
44 | assertThat(msgCaptor.getValue().toLowerCase(), containsString("executing"));
45 | assertThat(msgCaptor.getValue().toLowerCase(), containsString("env"));
46 | assertThat(msgCaptor.getValue().toLowerCase(), containsString("vars"));
47 | assertThat(commandCaptor.getValue(), containsString(command));
48 | }
49 |
50 | @Test
51 | public void expectedExitValueDoesNotLogError() throws Exception {
52 | processExecutor.exitValue(0);
53 |
54 | loggingProcessListener.afterFinish(null, new ProcessResult(0, null));
55 |
56 | ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(String.class);
57 | verify(logger).debug(msgCaptor.capture(), Matchers.any());
58 | assertThat(msgCaptor.getValue().toLowerCase(), containsString("process finished"));
59 |
60 | verify(logger, never()).error(anyString(), anyString());
61 | }
62 |
63 | @Test
64 | public void expectedExitValueDoesLogError() throws Exception {
65 | String command = RandomStringUtils.randomAlphabetic(5);
66 | ProcessExecutor processExecutor = new ProcessExecutor(command).exitValue(0);
67 | LoggingProcessListener loggingProcessListener = new LoggingProcessListener(logger);
68 | loggingProcessListener.beforeStart(processExecutor);
69 | loggingProcessListener.afterFinish(null, new ProcessResult(1, null));
70 |
71 | ArgumentCaptor msg = ArgumentCaptor.forClass(String.class);
72 | verify(logger).error(msg.capture(), anyString());
73 |
74 | assertThat(msg.getValue(), containsString("unexpected exit code"));
75 | }
76 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/bin/RabbitMqCommandTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 | import io.arivera.oss.embedded.rabbitmq.PredefinedVersion;
5 |
6 | import org.apache.commons.io.output.ByteArrayOutputStream;
7 | import org.apache.commons.lang3.ArrayUtils;
8 | import org.apache.commons.lang3.RandomStringUtils;
9 | import org.apache.commons.lang3.RandomUtils;
10 | import org.junit.Before;
11 | import org.junit.Rule;
12 | import org.junit.Test;
13 | import org.junit.rules.ExpectedException;
14 | import org.junit.rules.TemporaryFolder;
15 | import org.junit.runner.RunWith;
16 | import org.mockito.ArgumentCaptor;
17 | import org.mockito.Mock;
18 | import org.mockito.Mockito;
19 | import org.mockito.invocation.InvocationOnMock;
20 | import org.mockito.runners.MockitoJUnitRunner;
21 | import org.mockito.stubbing.Answer;
22 | import org.slf4j.Logger;
23 | import org.slf4j.LoggerFactory;
24 | import org.zeroturnaround.exec.ProcessExecutor;
25 | import org.zeroturnaround.exec.StartedProcess;
26 | import org.zeroturnaround.exec.listener.ProcessListener;
27 | import org.zeroturnaround.exec.stream.slf4j.Level;
28 | import org.zeroturnaround.exec.stream.slf4j.Slf4jErrorOutputStream;
29 | import org.zeroturnaround.exec.stream.slf4j.Slf4jInfoOutputStream;
30 | import org.zeroturnaround.exec.stream.slf4j.Slf4jOutputStream;
31 | import org.zeroturnaround.exec.stream.slf4j.Slf4jWarnOutputStream;
32 |
33 | import java.io.File;
34 | import java.io.IOException;
35 | import java.io.OutputStream;
36 | import java.util.Arrays;
37 | import java.util.HashMap;
38 | import java.util.List;
39 | import java.util.Map;
40 |
41 | import static org.hamcrest.CoreMatchers.containsString;
42 | import static org.hamcrest.CoreMatchers.endsWith;
43 | import static org.hamcrest.CoreMatchers.equalTo;
44 | import static org.hamcrest.CoreMatchers.hasItem;
45 | import static org.hamcrest.CoreMatchers.instanceOf;
46 | import static org.hamcrest.core.Is.is;
47 | import static org.junit.Assert.assertThat;
48 | import static org.junit.Assert.assertTrue;
49 | import static org.mockito.Mockito.atLeastOnce;
50 | import static org.mockito.Mockito.verify;
51 | import static org.mockito.Mockito.when;
52 |
53 | @RunWith(MockitoJUnitRunner.class)
54 | public class RabbitMqCommandTest {
55 |
56 | private static final Logger LOGGER = LoggerFactory.getLogger(RabbitMqCommandTest.class);
57 |
58 | @Rule
59 | public ExpectedException expectedException = ExpectedException.none();
60 |
61 | @Rule
62 | public TemporaryFolder tempFolder = new TemporaryFolder();
63 |
64 | @Mock
65 | private RabbitMqCommand.ProcessExecutorFactory factory;
66 |
67 | @Mock
68 | private StartedProcess startedProcess;
69 |
70 | private ProcessExecutor processExecutor;
71 |
72 | private String command;
73 | private RabbitMqCommand rabbitMqCommand;
74 | private File executableFile;
75 | private PredefinedVersion version;
76 | private EmbeddedRabbitMqConfig.Builder configBuilder;
77 |
78 | @Before
79 | public void setUp() throws Exception {
80 | version = PredefinedVersion.LATEST;
81 | configBuilder = new EmbeddedRabbitMqConfig.Builder()
82 | .extractionFolder(tempFolder.getRoot())
83 | .version(this.version)
84 | .processExecutorFactory(this.factory);
85 | command = RandomStringUtils.randomAlphabetic(10);
86 |
87 | this.processExecutor = Mockito.mock(ProcessExecutor.class, new Answer() {
88 | @Override
89 | public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
90 | if (invocationOnMock.getMethod().getName().equals("start")){
91 | return startedProcess;
92 | }
93 | return invocationOnMock.getMock();
94 | }
95 | });
96 |
97 | when(factory.createInstance()).thenReturn(processExecutor);
98 |
99 | String appFolder = version.getExtractionFolder();
100 | File executableFilesFolder = tempFolder.newFolder(appFolder, RabbitMqCommand.BINARIES_FOLDER);
101 | executableFile = new File(executableFilesFolder, command + RabbitMqCommand.getCommandExtension());
102 | assertTrue("Fake executable file couldn't be created!", executableFile.createNewFile());
103 | }
104 |
105 | @Test
106 | public void whenExecutableIsNotFound() throws Exception {
107 | executableFile.delete();
108 | expectedException.expect(IllegalArgumentException.class);
109 | expectedException.expectMessage(containsString("could not be found"));
110 | expectedException.expectMessage(containsString(command));
111 |
112 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
113 | }
114 |
115 | @Test
116 | public void processExecutesCommandWithArguments() throws Exception {
117 | String[] args = new String[RandomUtils.nextInt(0,10)];
118 | for(int i = 0; i < args.length; i++){
119 | args[i] = RandomStringUtils.randomAlphanumeric(5);
120 | }
121 |
122 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command, args);
123 | rabbitMqCommand.call();
124 |
125 | String[] commandAndArgs = ArrayUtils.add(args, 0, executableFile.toString());
126 | verify(processExecutor).command(Arrays.asList(commandAndArgs));
127 | }
128 |
129 | @Test
130 | public void processIncludesEnvironmentVars() throws Exception {
131 | Map envVars = new HashMap<>();
132 | envVars.put(RandomStringUtils.randomAlphanumeric(5), RandomStringUtils.randomAlphanumeric(10));
133 | envVars.put(RandomStringUtils.randomAlphanumeric(5), RandomStringUtils.randomAlphanumeric(10));
134 |
135 | configBuilder.envVars(envVars);
136 |
137 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
138 | rabbitMqCommand.call();
139 |
140 | verify(processExecutor).environment(envVars);
141 | }
142 |
143 | @Test
144 | public void processIsLaunchedFromAppDirectory() throws Exception {
145 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
146 | rabbitMqCommand.call();
147 |
148 | File binariesFolder = executableFile.getParentFile();
149 | File appFolder = binariesFolder.getParentFile();
150 | verify(processExecutor).directory(appFolder);
151 | }
152 |
153 | @Test
154 | public void processEventsAreLogged() throws Exception {
155 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
156 | rabbitMqCommand.call();
157 |
158 | ArgumentCaptor listenerCaptor = ArgumentCaptor.forClass(ProcessListener.class);
159 | verify(processExecutor, atLeastOnce()).addListener(listenerCaptor.capture());
160 |
161 | List listeners = listenerCaptor.getAllValues();
162 | boolean found = false;
163 | for (ProcessListener listener : listeners) {
164 | if (listener instanceof LoggingProcessListener){
165 | found = true;
166 | break;
167 | }
168 | }
169 | assertThat("Expected Listener was not found!", found, is(true));
170 | }
171 |
172 | @Test
173 | public void processEventsCanBeListenedTo() throws Exception {
174 | ProcessListener fakeListener = Mockito.mock(ProcessListener.class);
175 |
176 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
177 | rabbitMqCommand.listenToEvents(fakeListener);
178 | rabbitMqCommand.call();
179 |
180 | ArgumentCaptor listenerCaptor = ArgumentCaptor.forClass(ProcessListener.class);
181 | verify(processExecutor, atLeastOnce()).addListener(listenerCaptor.capture());
182 |
183 | List listeners = listenerCaptor.getAllValues();
184 | assertThat(listeners, hasItem(equalTo(fakeListener)));
185 | }
186 |
187 | @Test
188 | public void outputCanBeStreamed() throws Exception {
189 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
190 |
191 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
192 | rabbitMqCommand.writeOutputTo(byteArrayOutputStream);
193 | rabbitMqCommand.call();
194 |
195 | verify(processExecutor).redirectOutputAlsoTo(byteArrayOutputStream);
196 | }
197 |
198 | @Test
199 | public void errorOutputCanBeStreamed() throws Exception {
200 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
201 |
202 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
203 | rabbitMqCommand.writeErrorOutputTo(byteArrayOutputStream);
204 | rabbitMqCommand.call();
205 |
206 | verify(processExecutor).redirectErrorAlsoTo(byteArrayOutputStream);
207 | }
208 |
209 | @Test
210 | public void outputStorageCanBeDisabled() throws Exception {
211 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
212 | rabbitMqCommand.storeOutput(false);
213 | rabbitMqCommand.call();
214 |
215 | verify(processExecutor).readOutput(false);
216 | }
217 |
218 | @Test
219 | public void outputLoggingLevelsDefaultsToInfo() throws Exception {
220 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
221 | rabbitMqCommand.call();
222 |
223 | ArgumentCaptor osCaptor = ArgumentCaptor.forClass(OutputStream.class);
224 | verify(processExecutor).redirectOutput(osCaptor.capture());
225 |
226 | OutputStream os = osCaptor.getValue();
227 | assertThat(os, instanceOf(Slf4jInfoOutputStream.class));
228 | }
229 |
230 | @Test
231 | public void errorLoggingLevelDefaultsToWarn() throws Exception {
232 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
233 | rabbitMqCommand.call();
234 |
235 | ArgumentCaptor osCaptor = ArgumentCaptor.forClass(OutputStream.class);
236 | verify(processExecutor).redirectError(osCaptor.capture());
237 |
238 | OutputStream os = osCaptor.getValue();
239 | assertThat(os, instanceOf(Slf4jWarnOutputStream.class));
240 | }
241 |
242 | @Test
243 | public void errorLoggingLevelsCanBeChanged() throws Exception {
244 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
245 | rabbitMqCommand.logStandardErrorOutputAs(Level.ERROR);
246 | rabbitMqCommand.call();
247 |
248 | ArgumentCaptor osCaptor = ArgumentCaptor.forClass(OutputStream.class);
249 | verify(processExecutor).redirectError(osCaptor.capture());
250 |
251 | OutputStream os = osCaptor.getValue();
252 | assertThat(os, instanceOf(Slf4jErrorOutputStream.class));
253 | }
254 |
255 | @Test
256 | public void outputLoggingLevelsCanBeChanged() throws Exception {
257 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
258 | rabbitMqCommand.logStandardOutputAs(Level.ERROR);
259 | rabbitMqCommand.call();
260 |
261 | ArgumentCaptor osCaptor = ArgumentCaptor.forClass(OutputStream.class);
262 | verify(processExecutor).redirectOutput(osCaptor.capture());
263 |
264 | OutputStream os = osCaptor.getValue();
265 | assertThat(os, instanceOf(Slf4jErrorOutputStream.class));
266 | }
267 |
268 |
269 | @Test
270 | public void loggerCanBeChanged() throws Exception {
271 | Logger logger = Mockito.mock(Logger.class);
272 |
273 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
274 | rabbitMqCommand.logWith(logger);
275 | rabbitMqCommand.call();
276 |
277 | ArgumentCaptor osCaptor = ArgumentCaptor.forClass(OutputStream.class);
278 | verify(processExecutor).redirectOutput(osCaptor.capture());
279 |
280 | OutputStream os = osCaptor.getValue();
281 | assertThat(os, instanceOf(Slf4jOutputStream.class));
282 |
283 | Logger actualLogger = ((Slf4jOutputStream) os).getLogger();
284 | assertThat(actualLogger, is(logger));
285 | }
286 |
287 | @Test
288 | public void logNameMatchesCommandByDefault() throws Exception {
289 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
290 | rabbitMqCommand.call();
291 |
292 | ArgumentCaptor osCaptor = ArgumentCaptor.forClass(OutputStream.class);
293 | verify(processExecutor).redirectOutput(osCaptor.capture());
294 |
295 | OutputStream os = osCaptor.getValue();
296 | assertThat(os, instanceOf(Slf4jOutputStream.class));
297 |
298 | Logger logger = ((Slf4jOutputStream) os).getLogger();
299 | assertThat(logger.getName(), endsWith(command));
300 | }
301 |
302 | @Test
303 | public void processStartErrorIsWrapped() throws Exception {
304 | IOException fakeException = new IOException("fake!");
305 | when(processExecutor.start())
306 | .thenThrow(fakeException);
307 |
308 | expectedException.expect(RabbitMqCommandException.class);
309 | expectedException.expectMessage(containsString(command));
310 | expectedException.expectCause(equalTo(fakeException));
311 |
312 | rabbitMqCommand = new RabbitMqCommand(configBuilder.build(), command);
313 | rabbitMqCommand.call();
314 | }
315 |
316 | @Test
317 | public void defaultProcessExecutor(){
318 | ProcessExecutor executor = new RabbitMqCommand.ProcessExecutorFactory().createInstance();
319 | assertThat(executor, instanceOf(ProcessExecutor.class));
320 | }
321 |
322 | @Test
323 | public void defaultConstructor() throws Exception {
324 | new RabbitMqCommand(configBuilder.build(), command);
325 | }
326 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/bin/RabbitMqPluginsTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 | import io.arivera.oss.embedded.rabbitmq.PredefinedVersion;
5 | import io.arivera.oss.embedded.rabbitmq.bin.plugins.Plugin;
6 |
7 | import org.junit.Before;
8 | import org.junit.Rule;
9 | import org.junit.Test;
10 | import org.junit.rules.ExpectedException;
11 | import org.junit.rules.TemporaryFolder;
12 | import org.junit.runner.RunWith;
13 | import org.mockito.Mock;
14 | import org.mockito.Mockito;
15 | import org.mockito.invocation.InvocationOnMock;
16 | import org.mockito.runners.MockitoJUnitRunner;
17 | import org.mockito.stubbing.Answer;
18 | import org.zeroturnaround.exec.ProcessExecutor;
19 | import org.zeroturnaround.exec.ProcessOutput;
20 | import org.zeroturnaround.exec.ProcessResult;
21 | import org.zeroturnaround.exec.StartedProcess;
22 |
23 | import java.io.File;
24 | import java.util.Arrays;
25 | import java.util.List;
26 | import java.util.Map;
27 | import java.util.Random;
28 | import java.util.Set;
29 | import java.util.concurrent.Future;
30 | import java.util.concurrent.TimeUnit;
31 | import java.util.concurrent.TimeoutException;
32 |
33 | import static org.hamcrest.CoreMatchers.equalTo;
34 | import static org.hamcrest.CoreMatchers.instanceOf;
35 | import static org.hamcrest.CoreMatchers.sameInstance;
36 | import static org.junit.Assert.assertThat;
37 | import static org.junit.Assert.assertTrue;
38 | import static org.mockito.Matchers.any;
39 | import static org.mockito.Matchers.anyLong;
40 | import static org.mockito.Mockito.mock;
41 | import static org.mockito.Mockito.when;
42 |
43 | @RunWith(MockitoJUnitRunner.class)
44 | public class RabbitMqPluginsTest {
45 |
46 | @Rule
47 | public ExpectedException expectedException = ExpectedException.none();
48 | @Rule
49 | public TemporaryFolder tempFolder = new TemporaryFolder();
50 |
51 | @Mock
52 | private RabbitMqCommand.ProcessExecutorFactory factory;
53 | @Mock
54 | private StartedProcess startedProcess;
55 | @Mock
56 | private Future futureResult;
57 | @Mock
58 | private ProcessOutput processOutput;
59 | @Mock
60 | private ProcessResult result;
61 |
62 | private RabbitMqPlugins rabbitMqPlugins;
63 | private ProcessExecutor processExecutor;
64 | private File executableFile;
65 |
66 | @Before
67 | public void setUp() throws Exception {
68 | EmbeddedRabbitMqConfig embeddedRabbitMqConfig = new EmbeddedRabbitMqConfig.Builder()
69 | .extractionFolder(tempFolder.getRoot())
70 | .processExecutorFactory(factory)
71 | .build();
72 |
73 | this.processExecutor = Mockito.mock(ProcessExecutor.class, new Answer() {
74 | @Override
75 | public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
76 | if (invocationOnMock.getMethod().getName().equals("start")){
77 | return startedProcess;
78 | }
79 | return invocationOnMock.getMock();
80 | }
81 | });
82 |
83 | when(factory.createInstance()).thenReturn(processExecutor);
84 |
85 | rabbitMqPlugins = new RabbitMqPlugins(embeddedRabbitMqConfig);
86 |
87 | String appFolder = PredefinedVersion.LATEST.getExtractionFolder();
88 | File executableFilesFolder = tempFolder.newFolder(appFolder, RabbitMqCommand.BINARIES_FOLDER);
89 | executableFile = new File(executableFilesFolder, "rabbitmq-plugins" + RabbitMqCommand.getCommandExtension());
90 | assertTrue("Fake executable file couldn't be created!", executableFile.createNewFile());
91 | }
92 |
93 | @Test
94 | public void testListParsing() throws Exception {
95 | futureResult = mock(Future.class);
96 | result = mock(ProcessResult.class);
97 | when(startedProcess.getFuture())
98 | .thenReturn(futureResult);
99 | when(futureResult.get(anyLong(), any(TimeUnit.class)))
100 | .thenReturn(result);
101 | when(result.getExitValue())
102 | .thenReturn(0);
103 | processOutput = mock(ProcessOutput.class);
104 | when(result.getOutput())
105 | .thenReturn(processOutput);
106 |
107 | List output = Arrays.asList(
108 | " Configured: E = explicitly enabled; e = implicitly enabled ",
109 | " | Status: * = running on rabbit@rivera-mbp ",
110 | " |/ ",
111 | "[e*] amqp_client 3.5.7 ",
112 | "[ ] cowboy 0.5.0-rmq3.5.7-git4b93c2d",
113 | "[e*] mochiweb 2.7.0-rmq3.5.7-git680dba8",
114 | "[ ] rabbitmq_amqp1_0 3.5.7 ",
115 | "[E*] rabbitmq_management 3.5.7 ",
116 | "[e*] rabbitmq_management_agent 3.5.7 "
117 | );
118 | when(processOutput.getLinesAsUTF8())
119 | .thenReturn(output);
120 |
121 | Map> groupedPlugins =
122 | rabbitMqPlugins.groupedList();
123 |
124 | assertThat(groupedPlugins.get(Plugin.State.RUNNING).size(), equalTo(4));
125 | assertThat(groupedPlugins.get(Plugin.State.ENABLED_EXPLICITLY).size(), equalTo(1));
126 | assertThat(groupedPlugins.get(Plugin.State.ENABLED_IMPLICITLY).size(), equalTo(3));
127 | assertThat(groupedPlugins.get(Plugin.State.NOT_ENABLED).size(), equalTo(2));
128 | assertThat(groupedPlugins.get(Plugin.State.NOT_RUNNING).size(), equalTo(2));
129 | }
130 |
131 | @Test
132 | public void testUnexpectedExitCode() throws Exception {
133 | futureResult = mock(Future.class);
134 | result = mock(ProcessResult.class);
135 | when(startedProcess.getFuture())
136 | .thenReturn(futureResult);
137 | when(futureResult.get(anyLong(), any(TimeUnit.class)))
138 | .thenReturn(result);
139 | int exitCode = new Random().nextInt(10) + 1;
140 | when(result.getExitValue())
141 | .thenReturn(exitCode);
142 |
143 | expectedException.expect(instanceOf(RabbitMqCommandException.class));
144 | expectedException.expectMessage("exit code: " + exitCode);
145 |
146 | rabbitMqPlugins.groupedList();
147 | }
148 |
149 | @Test
150 | public void testExecutionError() throws Exception {
151 | futureResult = mock(Future.class);
152 | result = mock(ProcessResult.class);
153 | when(startedProcess.getFuture())
154 | .thenReturn(futureResult);
155 | TimeoutException timeoutException = new TimeoutException("Fake timeout");
156 | when(futureResult.get(anyLong(), any(TimeUnit.class)))
157 | .thenThrow(timeoutException);
158 |
159 | expectedException.expect(instanceOf(RabbitMqCommandException.class));
160 | expectedException.expectMessage("rabbitmq-plugins list");
161 | expectedException.expectCause(sameInstance(timeoutException));
162 |
163 | rabbitMqPlugins.groupedList();
164 | }
165 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/bin/plugins/PluginTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin.plugins;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.EnumSet;
6 | import java.util.regex.Pattern;
7 |
8 | import static org.hamcrest.CoreMatchers.equalTo;
9 | import static org.hamcrest.CoreMatchers.hasItems;
10 | import static org.junit.Assert.assertFalse;
11 | import static org.junit.Assert.assertThat;
12 | import static org.junit.Assert.assertTrue;
13 |
14 | public class PluginTest {
15 |
16 | public static final Pattern PATTERN = Plugin.LIST_OUTPUT_PATTERN;
17 |
18 | @Test
19 | public void testPatterns() throws Exception {
20 | assertTrue(PATTERN.matcher("[E*] rabbitmq_management 3.5.7").matches());
21 | assertTrue(PATTERN.matcher("[e ] mochiweb 2.7.0-rmq3.5.7-git680dba8").matches());
22 | assertTrue(PATTERN.matcher("[ ] rabbitmq_federation_management 3.5.7").matches());
23 | assertFalse(PATTERN.matcher(" Configured: E = explicitly enabled; e = implicitly enabled").matches());
24 | }
25 |
26 | @Test
27 | public void testNotEnabledPluginLine() throws Exception {
28 | String output = "[ ] rabbitmq_federation_management 3.5.7";
29 | Plugin plugin = Plugin.fromString(output);
30 |
31 | assertThat(plugin.getName(), equalTo("rabbitmq_federation_management"));
32 | assertThat(plugin.getVersion(), equalTo("3.5.7"));
33 | assertThat(plugin.getState(), equalTo(
34 | EnumSet.of(Plugin.State.NOT_ENABLED, Plugin.State.NOT_RUNNING)));
35 | }
36 |
37 | @Test
38 | public void testExplicitlyEnabledPluginLine() throws Exception {
39 | String output = "[E*] rabbitmq_management 3.5.7";
40 | Plugin plugin = Plugin.fromString(output);
41 | assertThat(plugin.getName(), equalTo("rabbitmq_management"));
42 | assertThat(plugin.getVersion(), equalTo("3.5.7"));
43 | assertThat(plugin.getState(), hasItems(
44 | Plugin.State.ENABLED_EXPLICITLY, Plugin.State.RUNNING));
45 | }
46 |
47 | @Test
48 | public void testImplicitlyEnabledPluginLine() throws Exception {
49 | String output = "[e ] mochiweb 2.7.0-rmq3.5.7-git680dba8";
50 | Plugin plugin = Plugin.fromString(output);
51 | assertThat(plugin.getName(), equalTo("mochiweb"));
52 | assertThat(plugin.getVersion(), equalTo("2.7.0-rmq3.5.7-git680dba8"));
53 | assertThat(plugin.getState(), hasItems(
54 | Plugin.State.ENABLED_IMPLICITLY, Plugin.State.NOT_RUNNING));
55 | }
56 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/bin/plugins/StateTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.bin.plugins;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.Set;
6 |
7 | import static org.hamcrest.CoreMatchers.hasItems;
8 | import static org.junit.Assert.assertThat;
9 |
10 | public class StateTest {
11 |
12 | @Test
13 | public void pluginStateEmpty() throws Exception {
14 | assertThat(Plugin.State.fromString(" "),
15 | hasItems(
16 | Plugin.State.NOT_ENABLED,
17 | Plugin.State.NOT_RUNNING));
18 | }
19 |
20 | @Test
21 | public void pluginStateExplicitRunning() throws Exception {
22 | Set states = Plugin.State.fromString("E*");
23 | assertThat(states, hasItems(
24 | Plugin.State.RUNNING,
25 | Plugin.State.ENABLED_EXPLICITLY));
26 | }
27 |
28 | @Test
29 | public void pluginStateImplicitRunning() throws Exception {
30 | Set states = Plugin.State.fromString("e*");
31 | assertThat(states, hasItems(
32 | Plugin.State.RUNNING,
33 | Plugin.State.ENABLED_IMPLICITLY));
34 | }
35 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/download/DownloaderFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.download;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import static org.junit.Assert.assertTrue;
9 |
10 | public class DownloaderFactoryTest {
11 |
12 | private EmbeddedRabbitMqConfig.Builder configBuilder;
13 |
14 | @Before
15 | public void setUp() throws Exception {
16 | configBuilder = new EmbeddedRabbitMqConfig.Builder();
17 | }
18 |
19 | @Test
20 | public void downloaderWithCaching() throws Exception {
21 | configBuilder.useCachedDownload(true);
22 |
23 | DownloaderFactory downloaderFactory = new DownloaderFactory(configBuilder.build());
24 | Downloader downloader = downloaderFactory.getNewInstance();
25 |
26 | assertTrue(downloader.getClass().equals(CachedDownloader.class));
27 | }
28 |
29 | @Test
30 | public void downloaderWithoutCaching() throws Exception {
31 | configBuilder.useCachedDownload(false);
32 |
33 | DownloaderFactory downloaderFactory = new DownloaderFactory(configBuilder.build());
34 | Downloader downloader = downloaderFactory.getNewInstance();
35 |
36 | assertTrue(downloader.getClass().equals(BasicDownloader.class));
37 | }
38 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/extract/ExtractorFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.extract;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.EmbeddedRabbitMqConfig;
4 |
5 | import org.junit.Before;
6 | import org.junit.Test;
7 |
8 | import static org.junit.Assert.assertTrue;
9 |
10 | public class ExtractorFactoryTest {
11 |
12 | private EmbeddedRabbitMqConfig.Builder builder;
13 |
14 | @Before
15 | public void setUp() throws Exception {
16 | builder = new EmbeddedRabbitMqConfig.Builder();
17 | }
18 |
19 | @Test
20 | public void withoutCaching() throws Exception {
21 | builder.useCachedDownload(false);
22 | Extractor extractor = new ExtractorFactory(builder.build()).getNewInstance();
23 |
24 | assertTrue(extractor.getClass().equals(BasicExtractor.class));
25 | }
26 |
27 | @Test
28 | public void withCaching() throws Exception {
29 | builder.useCachedDownload(true);
30 | Extractor extractor = new ExtractorFactory(builder.build()).getNewInstance();
31 |
32 | assertTrue(extractor.getClass().equals(CachedExtractor.class));
33 | }
34 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/helpers/ErlangVersionCheckerTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.helpers;
2 |
3 | import io.arivera.oss.embedded.rabbitmq.ErlangVersion;
4 | import io.arivera.oss.embedded.rabbitmq.bin.ErlangShell;
5 | import io.arivera.oss.embedded.rabbitmq.bin.ErlangShellException;
6 |
7 | import org.apache.commons.lang3.RandomStringUtils;
8 | import org.junit.Rule;
9 | import org.junit.Test;
10 | import org.junit.rules.ExpectedException;
11 | import org.junit.runner.RunWith;
12 | import org.mockito.Mock;
13 | import org.mockito.runners.MockitoJUnitRunner;
14 |
15 | import static org.hamcrest.CoreMatchers.containsString;
16 | import static org.hamcrest.CoreMatchers.equalTo;
17 | import static org.hamcrest.CoreMatchers.sameInstance;
18 | import static org.junit.Assert.assertThat;
19 | import static org.mockito.Mockito.when;
20 |
21 | @RunWith(MockitoJUnitRunner.class)
22 | public class ErlangVersionCheckerTest {
23 |
24 | @Rule
25 | public ExpectedException expectedException = ExpectedException.none();
26 | @Mock
27 | private ErlangShell shell;
28 |
29 | @Test
30 | public void parseR() {
31 | assertThat(ErlangVersionChecker.parse("R15B03-1"), equalTo(new int[] {15, 66, 3, 0, 0}));
32 | assertThat(ErlangVersionChecker.parse("R15B"), equalTo(new int[] {15, 66, 0, 0, 0}));
33 | assertThat(ErlangVersionChecker.parse("R11B-5"), equalTo(new int[] {11, 66, 0, 0, 0}));
34 | }
35 |
36 | @Test
37 | public void parseOtp() {
38 | assertThat(ErlangVersionChecker.parse("18.0"), equalTo(new int[] {18, 0, 0, 0, 0}));
39 | assertThat(ErlangVersionChecker.parse("18.2.1"), equalTo(new int[] {18, 2, 1, 0, 0}));
40 | assertThat(ErlangVersionChecker.parse("18.3"), equalTo(new int[] {18, 3, 0, 0, 0}));
41 | assertThat(ErlangVersionChecker.parse("19.3.6.4"), equalTo(new int[] {19, 3, 6, 4, 0}));
42 | }
43 |
44 | @Test
45 | public void parseConstants() {
46 | assertThat(ErlangVersionChecker.parse(ErlangVersion.R16B03), equalTo(new int[] {16, 66, 3, 0, 0}));
47 | assertThat(ErlangVersionChecker.parse(ErlangVersion.R13B03), equalTo(new int[] {13, 66, 3, 0, 0}));
48 | assertThat(ErlangVersionChecker.parse(ErlangVersion.V19_3), equalTo(new int[] {19, 3, 0, 0, 0}));
49 | assertThat(ErlangVersionChecker.parse(ErlangVersion.V19_3_6_4), equalTo(new int[] {19, 3, 6, 4, 0}));
50 | assertThat(ErlangVersionChecker.parse(ErlangVersion.V20_3), equalTo(new int[] {20, 3, 0, 0, 0}));
51 | assertThat(ErlangVersionChecker.parse(ErlangVersion.V21_3), equalTo(new int[] {21, 3, 0, 0, 0}));
52 | }
53 |
54 | @Test
55 | public void minVersionNotMet() throws ErlangShellException {
56 | when(shell.getErlangVersion()).thenReturn("R11B");
57 | expectedException.expect(ErlangVersionException.class);
58 | expectedException.expectMessage(containsString("Minimum required Erlang version"));
59 | expectedException.expectMessage(containsString("R11B"));
60 | expectedException.expectMessage(containsString("18.2.1"));
61 |
62 | ErlangVersionChecker checker = new ErlangVersionChecker("18.2.1", shell);
63 | checker.check();
64 | }
65 |
66 | @Test
67 | public void versionCannotBeDetermined() throws ErlangShellException {
68 | ErlangShellException erlangShellException = new ErlangShellException("fake!");
69 | when(shell.getErlangVersion()).thenThrow(erlangShellException);
70 | expectedException.expect(ErlangVersionException.class);
71 | expectedException.expectMessage(containsString("Could not determine Erlang version"));
72 | expectedException.expectMessage(containsString("Ensure Erlang is correctly installed"));
73 | expectedException.expectCause(sameInstance(erlangShellException));
74 |
75 | ErlangVersionChecker checker = new ErlangVersionChecker(RandomStringUtils.random(3), shell);
76 | checker.check();
77 | }
78 |
79 | @Test
80 | public void noRequiredVersion() throws ErlangShellException {
81 | when(shell.getErlangVersion()).thenReturn("18.2.1");
82 |
83 | String minErlangVersion = null;
84 | ErlangVersionChecker checker = new ErlangVersionChecker(minErlangVersion, shell);
85 | checker.check();
86 | }
87 |
88 | @Test
89 | public void versionCheckPasses() throws ErlangShellException {
90 | when(shell.getErlangVersion()).thenReturn("18.1");
91 |
92 | String minErlangVersion = "R14B01-3";
93 | ErlangVersionChecker checker = new ErlangVersionChecker(minErlangVersion, shell);
94 | checker.check();
95 | }
96 |
97 | @Test
98 | public void versionCheckPasses2() throws ErlangShellException {
99 | when(shell.getErlangVersion()).thenReturn("18.1.0");
100 | new ErlangVersionChecker("18.0.1", shell).check();
101 | }
102 |
103 | @Test(expected = ErlangVersionException.class)
104 | public void versionCheckFails() throws ErlangShellException {
105 | when(shell.getErlangVersion()).thenReturn("21.0.1");
106 | new ErlangVersionChecker("21.1.0", shell).check();
107 | }
108 |
109 | @Test
110 | public void versionCannotBeParsedFromActual() throws ErlangShellException {
111 | when(shell.getErlangVersion()).thenReturn("ABC");
112 | String minErlangVersion = "R14B01-3";
113 | ErlangVersionChecker checker = new ErlangVersionChecker(minErlangVersion, shell);
114 | checker.check();
115 | }
116 |
117 | @Test
118 | public void versionCannotBeParsedFromExpected() throws ErlangShellException {
119 | when(shell.getErlangVersion()).thenReturn("18.2.1");
120 | String minErlangVersion = "ABC";
121 | ErlangVersionChecker checker = new ErlangVersionChecker(minErlangVersion, shell);
122 | checker.check();
123 | }
124 | }
--------------------------------------------------------------------------------
/src/test/java/io/arivera/oss/embedded/rabbitmq/util/RandomPortSupplierTest.java:
--------------------------------------------------------------------------------
1 | package io.arivera.oss.embedded.rabbitmq.util;
2 |
3 | import org.junit.Test;
4 |
5 | import javax.net.ServerSocketFactory;
6 | import java.io.IOException;
7 | import java.net.ServerSocket;
8 |
9 | import static org.hamcrest.CoreMatchers.equalTo;
10 | import static org.hamcrest.CoreMatchers.not;
11 | import static org.hamcrest.CoreMatchers.notNullValue;
12 | import static org.junit.Assert.assertThat;
13 | import static org.mockito.Matchers.anyInt;
14 | import static org.mockito.Mockito.mock;
15 | import static org.mockito.Mockito.when;
16 |
17 | public class RandomPortSupplierTest {
18 |
19 | @Test
20 | public void testRandomPortIsReturned() throws IOException {
21 | int port = new RandomPortSupplier().get();
22 | assertThat(port, not(equalTo(0)));
23 | }
24 |
25 | @Test
26 | public void testPortIsAvailable() throws IOException {
27 | int port = new RandomPortSupplier().get();
28 | ServerSocket serverSocket = new ServerSocket(port);
29 | assertThat(serverSocket, notNullValue());
30 | serverSocket.close();
31 | }
32 |
33 | @Test(expected = IllegalStateException.class)
34 | public void testPortCantBeAssigned() throws IOException {
35 | ServerSocketFactory factory = mock(ServerSocketFactory.class);
36 | when(factory.createServerSocket(anyInt()))
37 | .thenThrow(new IOException("Fake"));
38 | new RandomPortSupplier(factory).get();
39 |
40 | }
41 | }
--------------------------------------------------------------------------------
/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | true
8 |
9 | UTF-8
10 |
11 | ${PATTERN}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------