From 999fb6c9e83add72a3e5773668f0dc8fa522a8ee Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 7 Feb 2019 15:03:44 +0100 Subject: [PATCH] Added checkstyle rules --- .circleci/config.yml | 4 +- .editorconfig | 18 + .gitignore | 3 +- .mvn/wrapper/MavenWrapperDownloader.java | 117 + .mvn/wrapper/maven-wrapper.jar | Bin 49502 -> 48337 bytes .mvn/wrapper/maven-wrapper.properties | 2 +- .settings.xml | 4 +- .../ConsulLifecycle.java => .springformat | 0 asciidoctor.css | 2404 ++++++++++++++--- docs/pom.xml | 4 +- mvnw | 177 +- mvnw.cmd | 161 ++ pom.xml | 37 +- scripts/build.sh | 1 + spring-cloud-consul-binder/pom.xml | 4 +- .../cloud/consul/binder/ConsulBinder.java | 23 +- .../binder/ConsulInboundMessageProducer.java | 35 +- .../consul/binder/ConsulSendingHandler.java | 20 +- .../cloud/consul/binder/EventService.java | 39 +- .../config/ConsulBinderConfiguration.java | 17 +- .../binder/config/ConsulBinderProperties.java | 7 +- .../consul-binder.properties | 1 - .../binder/ConsulBinderApplicationTests.java | 39 +- .../consul/binder/ConsulBinderTests.java | 127 +- .../ConsulInboundMessageProducerTests.java | 16 +- .../ConsulBinderConfigurationTests.java | 17 +- .../binder/test/consumer/TestConsumer.java | 27 +- .../binder/test/producer/TestProducer.java | 33 +- .../src/test/resources/application.yml | 1 - spring-cloud-consul-config/pom.xml | 4 +- .../cloud/consul/config/ConfigWatch.java | 141 +- .../config/ConsulConfigAutoConfiguration.java | 15 +- .../ConsulConfigBootstrapConfiguration.java | 9 +- .../consul/config/ConsulConfigProperties.java | 240 +- .../config/ConsulFilesPropertySource.java | 18 +- .../consul/config/ConsulPropertySource.java | 71 +- .../config/ConsulPropertySourceLocator.java | 55 +- .../config/PropertySourcesLocatedEvent.java | 14 +- .../main/resources/META-INF/spring.factories | 1 - .../cloud/consul/config/ConfigWatchTests.java | 44 +- ...nsulConfigBootstrapConfigurationTests.java | 67 +- .../config/ConsulPropertyPrefixTests.java | 53 +- ...tySourceLocatorAppNameCustomizedTests.java | 56 +- ...sulPropertySourceLocatorFailFastTests.java | 24 +- ...ConsulPropertySourceLocatorFilesTests.java | 101 +- .../ConsulPropertySourceLocatorTests.java | 175 +- .../config/ConsulPropertySourceTests.java | 75 +- spring-cloud-consul-core/pom.xml | 4 +- .../consul/ConditionalOnConsulEnabled.java | 30 +- .../cloud/consul/ConsulAutoConfiguration.java | 21 +- .../cloud/consul/ConsulEndpoint.java | 43 +- .../cloud/consul/ConsulHealthIndicator.java | 13 +- .../cloud/consul/ConsulProperties.java | 70 +- .../cloud/consul/RetryProperties.java | 37 +- .../cloud/consul/model/SerfStatusEnum.java | 27 +- .../consul/ConsulAutoConfigurationTests.java | 34 +- .../consul/ConsulHealthIndicatorDownTest.java | 29 +- .../consul/ConsulHealthIndicatorUpTest.java | 29 +- spring-cloud-consul-dependencies/pom.xml | 5 +- spring-cloud-consul-discovery/pom.xml | 4 +- .../consul/discovery/ConsulCatalogWatch.java | 52 +- .../discovery/ConsulDiscoveryClient.java | 51 +- .../ConsulDiscoveryClientConfiguration.java | 22 +- .../discovery/ConsulDiscoveryProperties.java | 248 +- .../cloud/consul/discovery/ConsulPing.java | 9 +- .../ConsulRibbonClientConfiguration.java | 16 +- .../cloud/consul/discovery/ConsulServer.java | 15 +- .../discovery/ConsulServerIntrospector.java | 27 +- .../consul/discovery/ConsulServerList.java | 28 +- .../consul/discovery/ConsulServerUtils.java | 40 +- .../HealthServiceServerListFilter.java | 16 +- .../consul/discovery/HeartbeatProperties.java | 70 +- .../RibbonConsulAutoConfiguration.java | 2 +- .../TestConsulLifecycleConfiguration.java | 0 .../cloud/consul/discovery/TtlScheduler.java | 28 +- .../ConsulConfigServerAutoConfiguration.java | 8 +- ...ntConfigServiceBootstrapConfiguration.java | 5 +- .../filters/AliveServerListFilter.java | 14 +- .../filters/FilteringAgentClient.java | 12 +- .../filters/ServiceCheckServerListFilter.java | 10 +- .../ConsulAutoRegistration.java | 182 +- .../ConsulAutoServiceRegistration.java | 18 +- ...oServiceRegistrationAutoConfiguration.java | 22 +- ...ConsulAutoServiceRegistrationListener.java | 31 +- ...onsulManagementRegistrationCustomizer.java | 6 + .../serviceregistry/ConsulRegistration.java | 22 +- .../ConsulRegistrationCustomizer.java | 4 +- .../ConsulServiceRegistry.java | 58 +- ...onsulServiceRegistryAutoConfiguration.java | 17 +- .../ConsulServletRegistrationCustomizer.java | 17 +- .../main/resources/META-INF/spring.factories | 2 - .../ConsulDiscoveryClientAclTests.java | 41 +- .../ConsulDiscoveryClientCustomizedTests.java | 45 +- ...ulDiscoveryClientDefaultQueryTagTests.java | 40 +- .../ConsulDiscoveryClientHttpsTests.java | 27 +- .../discovery/ConsulDiscoveryClientTests.java | 50 +- .../ConsulDiscoveryPropertiesTests.java | 62 +- .../ConsulLoadbalancerClientTests.java | 21 +- .../discovery/ConsulServerListAclTests.java | 62 +- .../discovery/ConsulServerListTests.java | 67 +- .../discovery/ConsulServerUtilsTest.java | 29 +- .../HealthServiceServerListFilterTests.java | 23 +- .../discovery/HeartbeatPropertiesTests.java | 38 +- .../discovery/TtlSchedulerRemoveTests.java | 59 +- .../consul/discovery/TtlSchedulerTests.java | 48 +- ...sulConfigServerAutoConfigurationTests.java | 28 +- ...ntConfigServiceAutoConfigurationTests.java | 27 +- ...DiscoveryClientBootstrapConfiguration.java | 10 +- ...toRegistrationHealthCheckHeadersTests.java | 12 +- ...strationHealthCheckTlsSkipVerifyTests.java | 5 +- ...utoServiceDeRegistrationDisabledTests.java | 92 +- ...gistrationCustomizedAgentAddressTests.java | 48 +- ...istrationCustomizedDiscoveryPortTests.java | 27 +- ...istrationCustomizedInstanceGroupTests.java | 53 +- ...gistrationCustomizedInstanceZoneTests.java | 43 +- ...nCustomizedManagementServicePortTests.java | 69 +- ...rviceRegistrationCustomizedPropsTests.java | 68 +- ...egistrationCustomizedServiceNameTests.java | 42 +- ...strationCustomizedServletContextTests.java | 32 +- ...utoServiceRegistrationCustomizedTests.java | 24 +- ...oServiceRegistrationDefaultCheckTests.java | 47 +- ...toServiceRegistrationDefaultPortTests.java | 36 +- ...lAutoServiceRegistrationDisabledTests.java | 34 +- ...lAutoServiceRegistrationFailFastTests.java | 25 +- ...RegistrationManagementCustomizerTests.java | 46 +- ...trationManagementDisabledServiceTests.java | 41 +- ...iceRegistrationManagementServiceTests.java | 64 +- ...sulAutoServiceRegistrationNonWebTests.java | 33 +- ...nsulAutoServiceRegistrationRetryTests.java | 26 +- .../ConsulAutoServiceRegistrationTests.java | 60 +- .../ConsulServiceRegistryCheckTtlTests.java | 49 +- .../ConsulServiceRegistryTests.java | 47 +- spring-cloud-consul-sample/pom.xml | 4 +- .../sample/SampleConsulApplication.java | 53 +- .../cloud/consul/sample/SampleProperties.java | 4 +- .../src/main/resources/application.yml | 2 +- spring-cloud-starter-consul-all/pom.xml | 5 +- .../main/resources/META-INF/spring.provides | 2 +- spring-cloud-starter-consul-bus/pom.xml | 5 +- .../main/resources/META-INF/spring.provides | 2 +- spring-cloud-starter-consul-config/pom.xml | 5 +- .../main/resources/META-INF/spring.provides | 2 +- spring-cloud-starter-consul-discovery/pom.xml | 4 +- .../main/resources/META-INF/spring.provides | 2 +- spring-cloud-starter-consul/pom.xml | 5 +- .../main/resources/META-INF/spring.provides | 2 +- src/checkstyle/checkstyle-suppressions.xml | 17 + src/main/bash/travis_install_consul.sh | 2 +- .../consul_acl/consul_anonymous_acl.json | 55 +- .../consul_discovery_client_acl.json | 35 +- .../resources/consul_config/acl_config.json | 8 +- src/test/resources/consul_ui/index.html | 164 +- .../consul_ui/static/application.min.js | 2 +- src/test/resources/consul_ui/static/base.css | 2070 ++++++++------ .../resources/consul_ui/static/base.css.map | 21 +- .../consul_ui/static/loading-cylon-purple.svg | 30 +- src/test/resources/etc/configserver.json | 10 +- 157 files changed, 6633 insertions(+), 3477 deletions(-) create mode 100644 .editorconfig create mode 100755 .mvn/wrapper/MavenWrapperDownloader.java mode change 100644 => 100755 .mvn/wrapper/maven-wrapper.jar mode change 100644 => 100755 .mvn/wrapper/maven-wrapper.properties rename spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulLifecycle.java => .springformat (100%) create mode 100755 mvnw.cmd delete mode 100644 spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/TestConsulLifecycleConfiguration.java create mode 100644 src/checkstyle/checkstyle-suppressions.xml diff --git a/.circleci/config.yml b/.circleci/config.yml index b1811623..0904aef7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ jobs: build: docker: - image: springcloud/pipeline-base -# user: appuser + # user: appuser environment: _JAVA_OPTIONS: "-Xms1024m -Xmx2048m" TERM: dumb @@ -43,4 +43,4 @@ jobs: destination: artifacts - store_test_results: path: ~/junit/ - destination: testartifacts \ No newline at end of file + destination: testartifacts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..0e33fa5c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = tab +indent_size = 4 +end_of_line = lf +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 + +[*.yaml] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore index d97cb9e8..861e8a80 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ _site/ .factorypath *.swp /consul -consul_*.zip \ No newline at end of file +consul_*.zip +consul_*.zip.* diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100755 index 00000000..f3e6046f --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is + * provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl + * property to use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for + * the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a + // custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, + MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream( + mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } + catch (IOException e) { + System.out.println( + "- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } + finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } + catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), + MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println("- ERROR creating output direcrory '" + + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } + catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) + throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar old mode 100644 new mode 100755 index 5fd4d5023f1463b5ba3970e33c460c1eb26d748d..01e67997377a393fd672c7dcde9dccbedf0cb1e9 GIT binary patch literal 48337 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%0A$pwhjXzyA0ZzErH{1@M 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 OJOEd-=rxTO#Qy`$*1Hh^ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties old mode 100644 new mode 100755 index 56bb0164..00d32aab --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip \ No newline at end of file +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip \ No newline at end of file diff --git a/.settings.xml b/.settings.xml index 270181b3..514b7e0e 100644 --- a/.settings.xml +++ b/.settings.xml @@ -10,7 +10,9 @@ spring - true + + true + spring-snapshots diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulLifecycle.java b/.springformat similarity index 100% rename from spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulLifecycle.java rename to .springformat diff --git a/asciidoctor.css b/asciidoctor.css index 06d52e68..ee4f1d81 100644 --- a/asciidoctor.css +++ b/asciidoctor.css @@ -1,399 +1,2011 @@ /* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */ /* Remove the comments around the @import statement below when using this as a custom stylesheet */ /*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic|Noto+Serif:400,400italic,700,700italic|Droid+Sans+Mono:400";*/ -article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block} -audio,canvas,video{display:inline-block} -audio:not([controls]){display:none;height:0} -[hidden],template{display:none} -script{display:none!important} -html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} -body{margin:0} -a{background:transparent} -a:focus{outline:thin dotted} -a:active,a:hover{outline:0} -h1{font-size:2em;margin:.67em 0} -abbr[title]{border-bottom:1px dotted} -b,strong{font-weight:bold} -dfn{font-style:italic} -hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0} -mark{background:#ff0;color:#000} -code,kbd,pre,samp{font-family:monospace;font-size:1em} -pre{white-space:pre-wrap} -q{quotes:"\201C" "\201D" "\2018" "\2019"} -small{font-size:80%} -sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} -sup{top:-.5em} -sub{bottom:-.25em} -img{border:0} -svg:not(:root){overflow:hidden} -figure{margin:0} -fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} -legend{border:0;padding:0} -button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} -button,input{line-height:normal} -button,select{text-transform:none} -button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer} -button[disabled],html input[disabled]{cursor:default} -input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0} -input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box} -input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none} -button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} -textarea{overflow:auto;vertical-align:top} -table{border-collapse:collapse;border-spacing:0} -*,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box} -html,body{font-size:100%} -body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto} -a:hover{cursor:pointer} -img,object,embed{max-width:100%;height:auto} -object,embed{height:100%} -img{-ms-interpolation-mode:bicubic} -#map_canvas img,#map_canvas embed,#map_canvas object,.map_canvas img,.map_canvas embed,.map_canvas object{max-width:none!important} -.left{float:left!important} -.right{float:right!important} -.text-left{text-align:left!important} -.text-right{text-align:right!important} -.text-center{text-align:center!important} -.text-justify{text-align:justify!important} -.hide{display:none} -.antialiased,body{-webkit-font-smoothing:antialiased} -img{display:inline-block;vertical-align:middle} -textarea{height:auto;min-height:50px} -select{width:100%} -p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{font-size:1.21875em;line-height:1.6} -.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} -div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr} -a{color:#2156a5;text-decoration:underline;line-height:inherit} -a:hover,a:focus{color:#1d4b8f} -a img{border:none} -p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} -p aside{font-size:.875em;line-height:1.35;font-style:italic} -h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} -h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0} -h1{font-size:2.125em} -h2{font-size:1.6875em} -h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} -h4,h5{font-size:1.125em} -h6{font-size:1em} -hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0} -em,i{font-style:italic;line-height:inherit} -strong,b{font-weight:bold;line-height:inherit} -small{font-size:60%;line-height:inherit} -code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} -ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} -ul,ol,ul.no-bullet,ol.no-bullet{margin-left:1.5em} -ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em} -ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit} -ul.square{list-style-type:square} -ul.circle{list-style-type:circle} -ul.disc{list-style-type:disc} -ul.no-bullet{list-style:none} -ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} -dl dt{margin-bottom:.3125em;font-weight:bold} -dl dd{margin-bottom:1.25em} -abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help} -abbr{text-transform:none} -blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} -blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)} -blockquote cite:before{content:"\2014 \0020"} -blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)} -blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} -@media only screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} -h1{font-size:2.75em} -h2{font-size:2.3125em} -h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} -h4{font-size:1.4375em}}table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede} -table thead,table tfoot{background:#f7f8f7;font-weight:bold} -table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left} -table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} -table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7} -table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6} -h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} -h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} -.clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table} -.clearfix:after,.float-group:after{clear:both} -*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed} -pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed} -.keyseq{color:rgba(51,51,51,.8)} -kbd{display:inline-block;color:rgba(0,0,0,.8);font-size:.75em;line-height:1.4;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:-.15em .15em 0 .15em;padding:.2em .6em .2em .5em;vertical-align:middle;white-space:nowrap} -.keyseq kbd:first-child{margin-left:0} -.keyseq kbd:last-child{margin-right:0} -.menuseq,.menu{color:rgba(0,0,0,.8)} -b.button:before,b.button:after{position:relative;top:-1px;font-weight:400} -b.button:before{content:"[";padding:0 3px 0 2px} -b.button:after{content:"]";padding:0 2px 0 3px} -p a>code:hover{color:rgba(0,0,0,.9)} -#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} -#header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table} -#header:after,#content:after,#footnotes:after,#footer:after{clear:both} -#content{margin-top:1.25em} -#content:before{content:none} -#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} -#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8} -#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px} -#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap} -#header .details span:first-child{margin-left:-.125em} -#header .details span.email a{color:rgba(0,0,0,.85)} -#header .details br{display:none} -#header .details br+span:before{content:"\00a0\2013\00a0"} -#header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} -#header .details br+span#revremark:before{content:"\00a0|\00a0"} -#header #revnumber{text-transform:capitalize} -#header #revnumber:after{content:"\00a0"} -#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem} -#toc{border-bottom:1px solid #efefed;padding-bottom:.5em} -#toc>ul{margin-left:.125em} -#toc ul.sectlevel0>li>a{font-style:italic} -#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} -#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} -#toc a{text-decoration:none} -#toc a:active{text-decoration:underline} -#toctitle{color:#7a2518;font-size:1.2em} -@media only screen and (min-width:768px){#toctitle{font-size:1.375em} -body.toc2{padding-left:15em;padding-right:0} -#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} -#toc.toc2 #toctitle{margin-top:0;font-size:1.2em} -#toc.toc2>ul{font-size:.9em;margin-bottom:0} -#toc.toc2 ul ul{margin-left:0;padding-left:1em} -#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} -body.toc2.toc-right{padding-left:0;padding-right:15em} -body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}@media only screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} -#toc.toc2{width:20em} -#toc.toc2 #toctitle{font-size:1.375em} -#toc.toc2>ul{font-size:.95em} -#toc.toc2 ul ul{padding-left:1.25em} -body.toc2.toc-right{padding-left:0;padding-right:20em}}#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} -#content #toc>:first-child{margin-top:0} -#content #toc>:last-child{margin-bottom:0} -#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em} -#footer-text{color:rgba(255,255,255,.8);line-height:1.44} -.sect1{padding-bottom:.625em} -@media only screen and (min-width:768px){.sect1{padding-bottom:1.25em}}.sect1+.sect1{border-top:1px solid #efefed} -#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} -#content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} -#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} -#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} -#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} -.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} -.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic} -table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0} -.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{color:rgba(0,0,0,.85)} -table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit} -.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} -.admonitionblock>table td.icon{text-align:center;width:80px} -.admonitionblock>table td.icon img{max-width:none} -.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} -.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)} -.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} -.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px} -.exampleblock>.content>:first-child{margin-top:0} -.exampleblock>.content>:last-child{margin-bottom:0} -.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} -.sidebarblock>:first-child{margin-top:0} -.sidebarblock>:last-child{margin-bottom:0} -.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center} -.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0} -.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8} -.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1} -.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em} -.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal} -@media only screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}@media only screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)} -.listingblock pre.highlightjs{padding:0} -.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px} -.listingblock pre.prettyprint{border-width:0} -.listingblock>.content{position:relative} -.listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999} -.listingblock:hover code[data-lang]:before{display:block} -.listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:.5em;color:#999} -.listingblock.terminal pre .command:not([data-prompt]):before{content:"$"} -table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none} -table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0} -table.pyhltable td.code{padding-left:.75em;padding-right:0} -pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8} -pre.pygments .lineno{display:inline-block;margin-right:.25em} -table.pyhltable .linenodiv{background:none!important;padding-right:0!important} -.quoteblock{margin:0 1em 1.25em 1.5em;display:table} -.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em} -.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} -.quoteblock blockquote{margin:0;padding:0;border:0} -.quoteblock blockquote:before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)} -.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} -.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right} -.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)} -.quoteblock .quoteblock blockquote{padding:0 0 0 .75em} -.quoteblock .quoteblock blockquote:before{display:none} -.verseblock{margin:0 1em 1.25em 1em} -.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} -.verseblock pre strong{font-weight:400} -.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} -.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} -.quoteblock .attribution br,.verseblock .attribution br{display:none} -.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.05em;color:rgba(0,0,0,.6)} -.quoteblock.abstract{margin:0 0 1.25em 0;display:block} -.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0} -.quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none} -table.tableblock{max-width:100%;border-collapse:separate} -table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0} -table.spread{width:100%} -table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} -table.grid-all th.tableblock,table.grid-all td.tableblock{border-width:0 1px 1px 0} -table.grid-all tfoot>tr>th.tableblock,table.grid-all tfoot>tr>td.tableblock{border-width:1px 1px 0 0} -table.grid-cols th.tableblock,table.grid-cols td.tableblock{border-width:0 1px 0 0} -table.grid-all *>tr>.tableblock:last-child,table.grid-cols *>tr>.tableblock:last-child{border-right-width:0} -table.grid-rows th.tableblock,table.grid-rows td.tableblock{border-width:0 0 1px 0} -table.grid-all tbody>tr:last-child>th.tableblock,table.grid-all tbody>tr:last-child>td.tableblock,table.grid-all thead:last-child>tr>th.tableblock,table.grid-rows tbody>tr:last-child>th.tableblock,table.grid-rows tbody>tr:last-child>td.tableblock,table.grid-rows thead:last-child>tr>th.tableblock{border-bottom-width:0} -table.grid-rows tfoot>tr>th.tableblock,table.grid-rows tfoot>tr>td.tableblock{border-width:1px 0 0 0} -table.frame-all{border-width:1px} -table.frame-sides{border-width:0 1px} -table.frame-topbot{border-width:1px 0} -th.halign-left,td.halign-left{text-align:left} -th.halign-right,td.halign-right{text-align:right} -th.halign-center,td.halign-center{text-align:center} -th.valign-top,td.valign-top{vertical-align:top} -th.valign-bottom,td.valign-bottom{vertical-align:bottom} -th.valign-middle,td.valign-middle{vertical-align:middle} -table thead th,table tfoot th{font-weight:bold} -tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7} -tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold} -p.tableblock>code:only-child{background:none;padding:0} -p.tableblock{font-size:1em} -td>div.verse{white-space:pre} -ol{margin-left:1.75em} -ul li ol{margin-left:1.5em} -dl dd{margin-left:1.125em} -dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} -ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} -ul.unstyled,ol.unnumbered,ul.checklist,ul.none{list-style-type:none} -ul.unstyled,ol.unnumbered,ul.checklist{margin-left:.625em} -ul.checklist li>p:first-child>.fa-check-square-o:first-child,ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em} -ul.checklist li>p:first-child>input[type="checkbox"]:first-child{position:relative;top:1px} -ul.inline{margin:0 auto .625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden} -ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block} -ul.inline>li>*{display:block} -.unstyled dl dt{font-weight:400;font-style:normal} -ol.arabic{list-style-type:decimal} -ol.decimal{list-style-type:decimal-leading-zero} -ol.loweralpha{list-style-type:lower-alpha} -ol.upperalpha{list-style-type:upper-alpha} -ol.lowerroman{list-style-type:lower-roman} -ol.upperroman{list-style-type:upper-roman} -ol.lowergreek{list-style-type:lower-greek} -.hdlist>table,.colist>table{border:0;background:none} -.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} -td.hdlist1{padding-right:.75em;font-weight:bold} -td.hdlist1,td.hdlist2{vertical-align:top} -.literalblock+.colist,.listingblock+.colist{margin-top:-.5em} -.colist>table tr>td:first-of-type{padding:0 .75em;line-height:1} -.colist>table tr>td:last-of-type{padding:.25em 0} -.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd} -.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0} -.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em} -.imageblock>.title{margin-bottom:0} -.imageblock.thumb,.imageblock.th{border-width:6px} -.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} -.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} -.image.left{margin-right:.625em} -.image.right{margin-left:.625em} -a.image{text-decoration:none} -span.footnote,span.footnoteref{vertical-align:super;font-size:.875em} -span.footnote a,span.footnoteref a{text-decoration:none} -span.footnote a:active,span.footnoteref a:active{text-decoration:underline} -#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} -#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em 0;border-width:1px 0 0 0} -#footnotes .footnote{padding:0 .375em;line-height:1.3;font-size:.875em;margin-left:1.2em;text-indent:-1.2em;margin-bottom:.2em} -#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none} -#footnotes .footnote:last-of-type{margin-bottom:0} -#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} -.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0} -.gist .file-data>table td.line-data{width:99%} -div.unbreakable{page-break-inside:avoid} -.big{font-size:larger} -.small{font-size:smaller} -.underline{text-decoration:underline} -.overline{text-decoration:overline} -.line-through{text-decoration:line-through} -.aqua{color:#00bfbf} -.aqua-background{background-color:#00fafa} -.black{color:#000} -.black-background{background-color:#000} -.blue{color:#0000bf} -.blue-background{background-color:#0000fa} -.fuchsia{color:#bf00bf} -.fuchsia-background{background-color:#fa00fa} -.gray{color:#606060} -.gray-background{background-color:#7d7d7d} -.green{color:#006000} -.green-background{background-color:#007d00} -.lime{color:#00bf00} -.lime-background{background-color:#00fa00} -.maroon{color:#600000} -.maroon-background{background-color:#7d0000} -.navy{color:#000060} -.navy-background{background-color:#00007d} -.olive{color:#606000} -.olive-background{background-color:#7d7d00} -.purple{color:#600060} -.purple-background{background-color:#7d007d} -.red{color:#bf0000} -.red-background{background-color:#fa0000} -.silver{color:#909090} -.silver-background{background-color:#bcbcbc} -.teal{color:#006060} -.teal-background{background-color:#007d7d} -.white{color:#bfbfbf} -.white-background{background-color:#fafafa} -.yellow{color:#bfbf00} -.yellow-background{background-color:#fafa00} -span.icon>.fa{cursor:default} -.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} -.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#19407c} -.admonitionblock td.icon .icon-tip:before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} -.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900} -.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400} -.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000} -.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} -.conum[data-value] *{color:#fff!important} -.conum[data-value]+b{display:none} -.conum[data-value]:after{content:attr(data-value)} -pre .conum[data-value]{position:relative;top:-.125em} -b.conum *{color:inherit!important} -.conum:not([data-value]):empty{display:none} -h1,h2{letter-spacing:-.01em} -dt,th.tableblock,td.content{text-rendering:optimizeLegibility} -p,td.content{letter-spacing:-.01em} -p strong,td.content strong{letter-spacing:-.005em} -p,blockquote,dt,td.content{font-size:1.0625rem} -p{margin-bottom:1.25rem} -.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} -.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc} -.print-only{display:none!important} -@media print{@page{margin:1.25cm .75cm} -*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important} -a{color:inherit!important;text-decoration:underline!important} -a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} -a[href^="http:"]:not(.bare):after,a[href^="https:"]:not(.bare):after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} -abbr[title]:after{content:" (" attr(title) ")"} -pre,blockquote,tr,img{page-break-inside:avoid} -thead{display:table-header-group} -img{max-width:100%!important} -p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} -h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} -#toc,.sidebarblock,.exampleblock>.content{background:none!important} -#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important} -.sect1{padding-bottom:0!important} -.sect1+.sect1{border:0!important} -#header>h1:first-child{margin-top:1.25rem} -body.book #header{text-align:center} -body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em 0} -body.book #header .details{border:0!important;display:block;padding:0!important} -body.book #header .details span:first-child{margin-left:0!important} -body.book #header .details br{display:block} -body.book #header .details br+span:before{content:none!important} -body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} -body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} -.listingblock code[data-lang]:before{display:block} -#footer{background:none!important;padding:0 .9375em} -#footer-text{color:rgba(0,0,0,.6)!important;font-size:.9em} -.hide-on-print{display:none!important} -.print-only{display:block!important} -.hide-for-print{display:none!important} -.show-for-print{display:inherit!important}} \ No newline at end of file +article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { + display: block +} + +audio, canvas, video { + display: inline-block +} + +audio:not([controls]) { + display: none; + height: 0 +} + +[hidden], template { + display: none +} + +script { + display: none !important +} + +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100% +} + +body { + margin: 0 +} + +a { + background: transparent +} + +a:focus { + outline: thin dotted +} + +a:active, a:hover { + outline: 0 +} + +h1 { + font-size: 2em; + margin: .67em 0 +} + +abbr[title] { + border-bottom: 1px dotted +} + +b, strong { + font-weight: bold +} + +dfn { + font-style: italic +} + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0 +} + +mark { + background: #ff0; + color: #000 +} + +code, kbd, pre, samp { + font-family: monospace; + font-size: 1em +} + +pre { + white-space: pre-wrap +} + +q { + quotes: "\201C" "\201D" "\2018" "\2019" +} + +small { + font-size: 80% +} + +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline +} + +sup { + top: -.5em +} + +sub { + bottom: -.25em +} + +img { + border: 0 +} + +svg:not(:root) { + overflow: hidden +} + +figure { + margin: 0 +} + +fieldset { + border: 1px solid silver; + margin: 0 2px; + padding: .35em .625em .75em +} + +legend { + border: 0; + padding: 0 +} + +button, input, select, textarea { + font-family: inherit; + font-size: 100%; + margin: 0 +} + +button, input { + line-height: normal +} + +button, select { + text-transform: none +} + +button, html input[type="button"], input[type="reset"], input[type="submit"] { + -webkit-appearance: button; + cursor: pointer +} + +button[disabled], html input[disabled] { + cursor: default +} + +input[type="checkbox"], input[type="radio"] { + box-sizing: border-box; + padding: 0 +} + +input[type="search"] { + -webkit-appearance: textfield; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box +} + +input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none +} + +button::-moz-focus-inner, input::-moz-focus-inner { + border: 0; + padding: 0 +} + +textarea { + overflow: auto; + vertical-align: top +} + +table { + border-collapse: collapse; + border-spacing: 0 +} + +*, *:before, *:after { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box +} + +html, body { + font-size: 100% +} + +body { + background: #fff; + color: rgba(0, 0, 0, .8); + padding: 0; + margin: 0; + font-family: "Noto Serif", "DejaVu Serif", serif; + font-weight: 400; + font-style: normal; + line-height: 1; + position: relative; + cursor: auto +} + +a:hover { + cursor: pointer +} + +img, object, embed { + max-width: 100%; + height: auto +} + +object, embed { + height: 100% +} + +img { + -ms-interpolation-mode: bicubic +} + +#map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { + max-width: none !important +} + +.left { + float: left !important +} + +.right { + float: right !important +} + +.text-left { + text-align: left !important +} + +.text-right { + text-align: right !important +} + +.text-center { + text-align: center !important +} + +.text-justify { + text-align: justify !important +} + +.hide { + display: none +} + +.antialiased, body { + -webkit-font-smoothing: antialiased +} + +img { + display: inline-block; + vertical-align: middle +} + +textarea { + height: auto; + min-height: 50px +} + +select { + width: 100% +} + +p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { + font-size: 1.21875em; + line-height: 1.6 +} + +.subheader, .admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { + line-height: 1.45; + color: #7a2518; + font-weight: 400; + margin-top: 0; + margin-bottom: .25em +} + +div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6, pre, form, p, blockquote, th, td { + margin: 0; + padding: 0; + direction: ltr +} + +a { + color: #2156a5; + text-decoration: underline; + line-height: inherit +} + +a:hover, a:focus { + color: #1d4b8f +} + +a img { + border: none +} + +p { + font-family: inherit; + font-weight: 400; + font-size: 1em; + line-height: 1.6; + margin-bottom: 1.25em; + text-rendering: optimizeLegibility +} + +p aside { + font-size: .875em; + line-height: 1.35; + font-style: italic +} + +h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { + font-family: "Open Sans", "DejaVu Sans", sans-serif; + font-weight: 300; + font-style: normal; + color: #ba3925; + text-rendering: optimizeLegibility; + margin-top: 1em; + margin-bottom: .5em; + line-height: 1.0125em +} + +h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small { + font-size: 60%; + color: #e99b8f; + line-height: 0 +} + +h1 { + font-size: 2.125em +} + +h2 { + font-size: 1.6875em +} + +h3, #toctitle, .sidebarblock > .content > .title { + font-size: 1.375em +} + +h4, h5 { + font-size: 1.125em +} + +h6 { + font-size: 1em +} + +hr { + border: solid #ddddd8; + border-width: 1px 0 0; + clear: both; + margin: 1.25em 0 1.1875em; + height: 0 +} + +em, i { + font-style: italic; + line-height: inherit +} + +strong, b { + font-weight: bold; + line-height: inherit +} + +small { + font-size: 60%; + line-height: inherit +} + +code { + font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace; + font-weight: 400; + color: rgba(0, 0, 0, .9) +} + +ul, ol, dl { + font-size: 1em; + line-height: 1.6; + margin-bottom: 1.25em; + list-style-position: outside; + font-family: inherit +} + +ul, ol, ul.no-bullet, ol.no-bullet { + margin-left: 1.5em +} + +ul li ul, ul li ol { + margin-left: 1.25em; + margin-bottom: 0; + font-size: 1em +} + +ul.square li ul, ul.circle li ul, ul.disc li ul { + list-style: inherit +} + +ul.square { + list-style-type: square +} + +ul.circle { + list-style-type: circle +} + +ul.disc { + list-style-type: disc +} + +ul.no-bullet { + list-style: none +} + +ol li ul, ol li ol { + margin-left: 1.25em; + margin-bottom: 0 +} + +dl dt { + margin-bottom: .3125em; + font-weight: bold +} + +dl dd { + margin-bottom: 1.25em +} + +abbr, acronym { + text-transform: uppercase; + font-size: 90%; + color: rgba(0, 0, 0, .8); + border-bottom: 1px dotted #ddd; + cursor: help +} + +abbr { + text-transform: none +} + +blockquote { + margin: 0 0 1.25em; + padding: .5625em 1.25em 0 1.1875em; + border-left: 1px solid #ddd +} + +blockquote cite { + display: block; + font-size: .9375em; + color: rgba(0, 0, 0, .6) +} + +blockquote cite:before { + content: "\2014 \0020" +} + +blockquote cite a, blockquote cite a:visited { + color: rgba(0, 0, 0, .6) +} + +blockquote, blockquote p { + line-height: 1.6; + color: rgba(0, 0, 0, .85) +} + +@media only screen and (min-width: 768px) { + h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { + line-height: 1.2 + } + + h1 { + font-size: 2.75em + } + + h2 { + font-size: 2.3125em + } + + h3, #toctitle, .sidebarblock > .content > .title { + font-size: 1.6875em + } + + h4 { + font-size: 1.4375em + } +} + +table { + background: #fff; + margin-bottom: 1.25em; + border: solid 1px #dedede +} + +table thead, table tfoot { + background: #f7f8f7; + font-weight: bold +} + +table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { + padding: .5em .625em .625em; + font-size: inherit; + color: rgba(0, 0, 0, .8); + text-align: left +} + +table tr th, table tr td { + padding: .5625em .625em; + font-size: inherit; + color: rgba(0, 0, 0, .8) +} + +table tr.even, table tr.alt, table tr:nth-of-type(even) { + background: #f8f8f7 +} + +table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { + display: table-cell; + line-height: 1.6 +} + +h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { + line-height: 1.2; + word-spacing: -.05em +} + +h1 strong, h2 strong, h3 strong, #toctitle strong, .sidebarblock > .content > .title strong, h4 strong, h5 strong, h6 strong { + font-weight: 400 +} + +.clearfix:before, .clearfix:after, .float-group:before, .float-group:after { + content: " "; + display: table +} + +.clearfix:after, .float-group:after { + clear: both +} + +*:not(pre) > code { + font-size: .9375em; + font-style: normal !important; + letter-spacing: 0; + padding: .1em .5ex; + word-spacing: -.15em; + background-color: #f7f7f8; + -webkit-border-radius: 4px; + border-radius: 4px; + line-height: 1.45; + text-rendering: optimizeSpeed +} + +pre, pre > code { + line-height: 1.45; + color: rgba(0, 0, 0, .9); + font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace; + font-weight: 400; + text-rendering: optimizeSpeed +} + +.keyseq { + color: rgba(51, 51, 51, .8) +} + +kbd { + display: inline-block; + color: rgba(0, 0, 0, .8); + font-size: .75em; + line-height: 1.4; + background-color: #f7f7f7; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 0 0 .1em white inset; + box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 0 0 .1em #fff inset; + margin: -.15em .15em 0 .15em; + padding: .2em .6em .2em .5em; + vertical-align: middle; + white-space: nowrap +} + +.keyseq kbd:first-child { + margin-left: 0 +} + +.keyseq kbd:last-child { + margin-right: 0 +} + +.menuseq, .menu { + color: rgba(0, 0, 0, .8) +} + +b.button:before, b.button:after { + position: relative; + top: -1px; + font-weight: 400 +} + +b.button:before { + content: "["; + padding: 0 3px 0 2px +} + +b.button:after { + content: "]"; + padding: 0 2px 0 3px +} + +p a > code:hover { + color: rgba(0, 0, 0, .9) +} + +#header, #content, #footnotes, #footer { + width: 100%; + margin-left: auto; + margin-right: auto; + margin-top: 0; + margin-bottom: 0; + max-width: 62.5em; + *zoom: 1; + position: relative; + padding-left: .9375em; + padding-right: .9375em +} + +#header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { + content: " "; + display: table +} + +#header:after, #content:after, #footnotes:after, #footer:after { + clear: both +} + +#content { + margin-top: 1.25em +} + +#content:before { + content: none +} + +#header > h1:first-child { + color: rgba(0, 0, 0, .85); + margin-top: 2.25rem; + margin-bottom: 0 +} + +#header > h1:first-child + #toc { + margin-top: 8px; + border-top: 1px solid #ddddd8 +} + +#header > h1:only-child, body.toc2 #header > h1:nth-last-child(2) { + border-bottom: 1px solid #ddddd8; + padding-bottom: 8px +} + +#header .details { + border-bottom: 1px solid #ddddd8; + line-height: 1.45; + padding-top: .25em; + padding-bottom: .25em; + padding-left: .25em; + color: rgba(0, 0, 0, .6); + display: -ms-flexbox; + display: -webkit-flex; + display: flex; + -ms-flex-flow: row wrap; + -webkit-flex-flow: row wrap; + flex-flow: row wrap +} + +#header .details span:first-child { + margin-left: -.125em +} + +#header .details span.email a { + color: rgba(0, 0, 0, .85) +} + +#header .details br { + display: none +} + +#header .details br + span:before { + content: "\00a0\2013\00a0" +} + +#header .details br + span.author:before { + content: "\00a0\22c5\00a0"; + color: rgba(0, 0, 0, .85) +} + +#header .details br + span#revremark:before { + content: "\00a0|\00a0" +} + +#header #revnumber { + text-transform: capitalize +} + +#header #revnumber:after { + content: "\00a0" +} + +#content > h1:first-child:not([class]) { + color: rgba(0, 0, 0, .85); + border-bottom: 1px solid #ddddd8; + padding-bottom: 8px; + margin-top: 0; + padding-top: 1rem; + margin-bottom: 1.25rem +} + +#toc { + border-bottom: 1px solid #efefed; + padding-bottom: .5em +} + +#toc > ul { + margin-left: .125em +} + +#toc ul.sectlevel0 > li > a { + font-style: italic +} + +#toc ul.sectlevel0 ul.sectlevel1 { + margin: .5em 0 +} + +#toc ul { + font-family: "Open Sans", "DejaVu Sans", sans-serif; + list-style-type: none +} + +#toc a { + text-decoration: none +} + +#toc a:active { + text-decoration: underline +} + +#toctitle { + color: #7a2518; + font-size: 1.2em +} + +@media only screen and (min-width: 768px) { + #toctitle { + font-size: 1.375em + } + + body.toc2 { + padding-left: 15em; + padding-right: 0 + } + + #toc.toc2 { + margin-top: 0 !important; + background-color: #f8f8f7; + position: fixed; + width: 15em; + left: 0; + top: 0; + border-right: 1px solid #efefed; + border-top-width: 0 !important; + border-bottom-width: 0 !important; + z-index: 1000; + padding: 1.25em 1em; + height: 100%; + overflow: auto + } + + #toc.toc2 #toctitle { + margin-top: 0; + font-size: 1.2em + } + + #toc.toc2 > ul { + font-size: .9em; + margin-bottom: 0 + } + + #toc.toc2 ul ul { + margin-left: 0; + padding-left: 1em + } + + #toc.toc2 ul.sectlevel0 ul.sectlevel1 { + padding-left: 0; + margin-top: .5em; + margin-bottom: .5em + } + + body.toc2.toc-right { + padding-left: 0; + padding-right: 15em + } + + body.toc2.toc-right #toc.toc2 { + border-right-width: 0; + border-left: 1px solid #efefed; + left: auto; + right: 0 + } +} + +@media only screen and (min-width: 1280px) { + body.toc2 { + padding-left: 20em; + padding-right: 0 + } + + #toc.toc2 { + width: 20em + } + + #toc.toc2 #toctitle { + font-size: 1.375em + } + + #toc.toc2 > ul { + font-size: .95em + } + + #toc.toc2 ul ul { + padding-left: 1.25em + } + + body.toc2.toc-right { + padding-left: 0; + padding-right: 20em + } +} + +#content #toc { + border-style: solid; + border-width: 1px; + border-color: #e0e0dc; + margin-bottom: 1.25em; + padding: 1.25em; + background: #f8f8f7; + -webkit-border-radius: 4px; + border-radius: 4px +} + +#content #toc > :first-child { + margin-top: 0 +} + +#content #toc > :last-child { + margin-bottom: 0 +} + +#footer { + max-width: 100%; + background-color: rgba(0, 0, 0, .8); + padding: 1.25em +} + +#footer-text { + color: rgba(255, 255, 255, .8); + line-height: 1.44 +} + +.sect1 { + padding-bottom: .625em +} + +@media only screen and (min-width: 768px) { + .sect1 { + padding-bottom: 1.25em + } +} + +.sect1 + .sect1 { + border-top: 1px solid #efefed +} + +#content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { + position: absolute; + z-index: 1001; + width: 1.5ex; + margin-left: -1.5ex; + display: block; + text-decoration: none !important; + visibility: hidden; + text-align: center; + font-weight: 400 +} + +#content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before { + content: "\00A7"; + font-size: .85em; + display: block; + padding-top: .1em +} + +#content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover { + visibility: visible +} + +#content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link { + color: #ba3925; + text-decoration: none +} + +#content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover { + color: #a53221 +} + +.audioblock, .imageblock, .literalblock, .listingblock, .stemblock, .videoblock { + margin-bottom: 1.25em +} + +.admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { + text-rendering: optimizeLegibility; + text-align: left; + font-family: "Noto Serif", "DejaVu Serif", serif; + font-size: 1rem; + font-style: italic +} + +table.tableblock > caption.title { + white-space: nowrap; + overflow: visible; + max-width: 0 +} + +.paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { + color: rgba(0, 0, 0, .85) +} + +table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { + font-size: inherit +} + +.admonitionblock > table { + border-collapse: separate; + border: 0; + background: none; + width: 100% +} + +.admonitionblock > table td.icon { + text-align: center; + width: 80px +} + +.admonitionblock > table td.icon img { + max-width: none +} + +.admonitionblock > table td.icon .title { + font-weight: bold; + font-family: "Open Sans", "DejaVu Sans", sans-serif; + text-transform: uppercase +} + +.admonitionblock > table td.content { + padding-left: 1.125em; + padding-right: 1.25em; + border-left: 1px solid #ddddd8; + color: rgba(0, 0, 0, .6) +} + +.admonitionblock > table td.content > :last-child > :last-child { + margin-bottom: 0 +} + +.exampleblock > .content { + border-style: solid; + border-width: 1px; + border-color: #e6e6e6; + margin-bottom: 1.25em; + padding: 1.25em; + background: #fff; + -webkit-border-radius: 4px; + border-radius: 4px +} + +.exampleblock > .content > :first-child { + margin-top: 0 +} + +.exampleblock > .content > :last-child { + margin-bottom: 0 +} + +.sidebarblock { + border-style: solid; + border-width: 1px; + border-color: #e0e0dc; + margin-bottom: 1.25em; + padding: 1.25em; + background: #f8f8f7; + -webkit-border-radius: 4px; + border-radius: 4px +} + +.sidebarblock > :first-child { + margin-top: 0 +} + +.sidebarblock > :last-child { + margin-bottom: 0 +} + +.sidebarblock > .content > .title { + color: #7a2518; + margin-top: 0; + text-align: center +} + +.exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child { + margin-bottom: 0 +} + +.literalblock pre, .listingblock pre:not(.highlight), .listingblock pre[class="highlight"], .listingblock pre[class^="highlight "], .listingblock pre.CodeRay, .listingblock pre.prettyprint { + background: #f7f7f8 +} + +.sidebarblock .literalblock pre, .sidebarblock .listingblock pre:not(.highlight), .sidebarblock .listingblock pre[class="highlight"], .sidebarblock .listingblock pre[class^="highlight "], .sidebarblock .listingblock pre.CodeRay, .sidebarblock .listingblock pre.prettyprint { + background: #f2f1f1 +} + +.literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { + -webkit-border-radius: 4px; + border-radius: 4px; + word-wrap: break-word; + padding: 1em; + font-size: .8125em +} + +.literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { + overflow-x: auto; + white-space: pre; + word-wrap: normal +} + +@media only screen and (min-width: 768px) { + .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { + font-size: .90625em + } +} + +@media only screen and (min-width: 1280px) { + .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { + font-size: 1em + } +} + +.literalblock.output pre { + color: #f7f7f8; + background-color: rgba(0, 0, 0, .9) +} + +.listingblock pre.highlightjs { + padding: 0 +} + +.listingblock pre.highlightjs > code { + padding: 1em; + -webkit-border-radius: 4px; + border-radius: 4px +} + +.listingblock pre.prettyprint { + border-width: 0 +} + +.listingblock > .content { + position: relative +} + +.listingblock code[data-lang]:before { + display: none; + content: attr(data-lang); + position: absolute; + font-size: .75em; + top: .425rem; + right: .5rem; + line-height: 1; + text-transform: uppercase; + color: #999 +} + +.listingblock:hover code[data-lang]:before { + display: block +} + +.listingblock.terminal pre .command:before { + content: attr(data-prompt); + padding-right: .5em; + color: #999 +} + +.listingblock.terminal pre .command:not([data-prompt]):before { + content: "$" +} + +table.pyhltable { + border-collapse: separate; + border: 0; + margin-bottom: 0; + background: none +} + +table.pyhltable td { + vertical-align: top; + padding-top: 0; + padding-bottom: 0 +} + +table.pyhltable td.code { + padding-left: .75em; + padding-right: 0 +} + +pre.pygments .lineno, table.pyhltable td:not(.code) { + color: #999; + padding-left: 0; + padding-right: .5em; + border-right: 1px solid #ddddd8 +} + +pre.pygments .lineno { + display: inline-block; + margin-right: .25em +} + +table.pyhltable .linenodiv { + background: none !important; + padding-right: 0 !important +} + +.quoteblock { + margin: 0 1em 1.25em 1.5em; + display: table +} + +.quoteblock > .title { + margin-left: -1.5em; + margin-bottom: .75em +} + +.quoteblock blockquote, .quoteblock blockquote p { + color: rgba(0, 0, 0, .85); + font-size: 1.15rem; + line-height: 1.75; + word-spacing: .1em; + letter-spacing: 0; + font-style: italic; + text-align: justify +} + +.quoteblock blockquote { + margin: 0; + padding: 0; + border: 0 +} + +.quoteblock blockquote:before { + content: "\201c"; + float: left; + font-size: 2.75em; + font-weight: bold; + line-height: .6em; + margin-left: -.6em; + color: #7a2518; + text-shadow: 0 1px 2px rgba(0, 0, 0, .1) +} + +.quoteblock blockquote > .paragraph:last-child p { + margin-bottom: 0 +} + +.quoteblock .attribution { + margin-top: .5em; + margin-right: .5ex; + text-align: right +} + +.quoteblock .quoteblock { + margin-left: 0; + margin-right: 0; + padding: .5em 0; + border-left: 3px solid rgba(0, 0, 0, .6) +} + +.quoteblock .quoteblock blockquote { + padding: 0 0 0 .75em +} + +.quoteblock .quoteblock blockquote:before { + display: none +} + +.verseblock { + margin: 0 1em 1.25em 1em +} + +.verseblock pre { + font-family: "Open Sans", "DejaVu Sans", sans; + font-size: 1.15rem; + color: rgba(0, 0, 0, .85); + font-weight: 300; + text-rendering: optimizeLegibility +} + +.verseblock pre strong { + font-weight: 400 +} + +.verseblock .attribution { + margin-top: 1.25rem; + margin-left: .5ex +} + +.quoteblock .attribution, .verseblock .attribution { + font-size: .9375em; + line-height: 1.45; + font-style: italic +} + +.quoteblock .attribution br, .verseblock .attribution br { + display: none +} + +.quoteblock .attribution cite, .verseblock .attribution cite { + display: block; + letter-spacing: -.05em; + color: rgba(0, 0, 0, .6) +} + +.quoteblock.abstract { + margin: 0 0 1.25em 0; + display: block +} + +.quoteblock.abstract blockquote, .quoteblock.abstract blockquote p { + text-align: left; + word-spacing: 0 +} + +.quoteblock.abstract blockquote:before, .quoteblock.abstract blockquote p:first-of-type:before { + display: none +} + +table.tableblock { + max-width: 100%; + border-collapse: separate +} + +table.tableblock td > .paragraph:last-child p > p:last-child, table.tableblock th > p:last-child, table.tableblock td > p:last-child { + margin-bottom: 0 +} + +table.spread { + width: 100% +} + +table.tableblock, th.tableblock, td.tableblock { + border: 0 solid #dedede +} + +table.grid-all th.tableblock, table.grid-all td.tableblock { + border-width: 0 1px 1px 0 +} + +table.grid-all tfoot > tr > th.tableblock, table.grid-all tfoot > tr > td.tableblock { + border-width: 1px 1px 0 0 +} + +table.grid-cols th.tableblock, table.grid-cols td.tableblock { + border-width: 0 1px 0 0 +} + +table.grid-all * > tr > .tableblock:last-child, table.grid-cols * > tr > .tableblock:last-child { + border-right-width: 0 +} + +table.grid-rows th.tableblock, table.grid-rows td.tableblock { + border-width: 0 0 1px 0 +} + +table.grid-all tbody > tr:last-child > th.tableblock, table.grid-all tbody > tr:last-child > td.tableblock, table.grid-all thead:last-child > tr > th.tableblock, table.grid-rows tbody > tr:last-child > th.tableblock, table.grid-rows tbody > tr:last-child > td.tableblock, table.grid-rows thead:last-child > tr > th.tableblock { + border-bottom-width: 0 +} + +table.grid-rows tfoot > tr > th.tableblock, table.grid-rows tfoot > tr > td.tableblock { + border-width: 1px 0 0 0 +} + +table.frame-all { + border-width: 1px +} + +table.frame-sides { + border-width: 0 1px +} + +table.frame-topbot { + border-width: 1px 0 +} + +th.halign-left, td.halign-left { + text-align: left +} + +th.halign-right, td.halign-right { + text-align: right +} + +th.halign-center, td.halign-center { + text-align: center +} + +th.valign-top, td.valign-top { + vertical-align: top +} + +th.valign-bottom, td.valign-bottom { + vertical-align: bottom +} + +th.valign-middle, td.valign-middle { + vertical-align: middle +} + +table thead th, table tfoot th { + font-weight: bold +} + +tbody tr th { + display: table-cell; + line-height: 1.6; + background: #f7f8f7 +} + +tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p { + color: rgba(0, 0, 0, .8); + font-weight: bold +} + +p.tableblock > code:only-child { + background: none; + padding: 0 +} + +p.tableblock { + font-size: 1em +} + +td > div.verse { + white-space: pre +} + +ol { + margin-left: 1.75em +} + +ul li ol { + margin-left: 1.5em +} + +dl dd { + margin-left: 1.125em +} + +dl dd:last-child, dl dd:last-child > :last-child { + margin-bottom: 0 +} + +ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { + margin-bottom: .625em +} + +ul.unstyled, ol.unnumbered, ul.checklist, ul.none { + list-style-type: none +} + +ul.unstyled, ol.unnumbered, ul.checklist { + margin-left: .625em +} + +ul.checklist li > p:first-child > .fa-check-square-o:first-child, ul.checklist li > p:first-child > input[type="checkbox"]:first-child { + margin-right: .25em +} + +ul.checklist li > p:first-child > input[type="checkbox"]:first-child { + position: relative; + top: 1px +} + +ul.inline { + margin: 0 auto .625em auto; + margin-left: -1.375em; + margin-right: 0; + padding: 0; + list-style: none; + overflow: hidden +} + +ul.inline > li { + list-style: none; + float: left; + margin-left: 1.375em; + display: block +} + +ul.inline > li > * { + display: block +} + +.unstyled dl dt { + font-weight: 400; + font-style: normal +} + +ol.arabic { + list-style-type: decimal +} + +ol.decimal { + list-style-type: decimal-leading-zero +} + +ol.loweralpha { + list-style-type: lower-alpha +} + +ol.upperalpha { + list-style-type: upper-alpha +} + +ol.lowerroman { + list-style-type: lower-roman +} + +ol.upperroman { + list-style-type: upper-roman +} + +ol.lowergreek { + list-style-type: lower-greek +} + +.hdlist > table, .colist > table { + border: 0; + background: none +} + +.hdlist > table > tbody > tr, .colist > table > tbody > tr { + background: none +} + +td.hdlist1 { + padding-right: .75em; + font-weight: bold +} + +td.hdlist1, td.hdlist2 { + vertical-align: top +} + +.literalblock + .colist, .listingblock + .colist { + margin-top: -.5em +} + +.colist > table tr > td:first-of-type { + padding: 0 .75em; + line-height: 1 +} + +.colist > table tr > td:last-of-type { + padding: .25em 0 +} + +.thumb, .th { + line-height: 0; + display: inline-block; + border: solid 4px #fff; + -webkit-box-shadow: 0 0 0 1px #ddd; + box-shadow: 0 0 0 1px #ddd +} + +.imageblock.left, .imageblock[style*="float: left"] { + margin: .25em .625em 1.25em 0 +} + +.imageblock.right, .imageblock[style*="float: right"] { + margin: .25em 0 1.25em .625em +} + +.imageblock > .title { + margin-bottom: 0 +} + +.imageblock.thumb, .imageblock.th { + border-width: 6px +} + +.imageblock.thumb > .title, .imageblock.th > .title { + padding: 0 .125em +} + +.image.left, .image.right { + margin-top: .25em; + margin-bottom: .25em; + display: inline-block; + line-height: 0 +} + +.image.left { + margin-right: .625em +} + +.image.right { + margin-left: .625em +} + +a.image { + text-decoration: none +} + +span.footnote, span.footnoteref { + vertical-align: super; + font-size: .875em +} + +span.footnote a, span.footnoteref a { + text-decoration: none +} + +span.footnote a:active, span.footnoteref a:active { + text-decoration: underline +} + +#footnotes { + padding-top: .75em; + padding-bottom: .75em; + margin-bottom: .625em +} + +#footnotes hr { + width: 20%; + min-width: 6.25em; + margin: -.25em 0 .75em 0; + border-width: 1px 0 0 0 +} + +#footnotes .footnote { + padding: 0 .375em; + line-height: 1.3; + font-size: .875em; + margin-left: 1.2em; + text-indent: -1.2em; + margin-bottom: .2em +} + +#footnotes .footnote a:first-of-type { + font-weight: bold; + text-decoration: none +} + +#footnotes .footnote:last-of-type { + margin-bottom: 0 +} + +#content #footnotes { + margin-top: -.625em; + margin-bottom: 0; + padding: .75em 0 +} + +.gist .file-data > table { + border: 0; + background: #fff; + width: 100%; + margin-bottom: 0 +} + +.gist .file-data > table td.line-data { + width: 99% +} + +div.unbreakable { + page-break-inside: avoid +} + +.big { + font-size: larger +} + +.small { + font-size: smaller +} + +.underline { + text-decoration: underline +} + +.overline { + text-decoration: overline +} + +.line-through { + text-decoration: line-through +} + +.aqua { + color: #00bfbf +} + +.aqua-background { + background-color: #00fafa +} + +.black { + color: #000 +} + +.black-background { + background-color: #000 +} + +.blue { + color: #0000bf +} + +.blue-background { + background-color: #0000fa +} + +.fuchsia { + color: #bf00bf +} + +.fuchsia-background { + background-color: #fa00fa +} + +.gray { + color: #606060 +} + +.gray-background { + background-color: #7d7d7d +} + +.green { + color: #006000 +} + +.green-background { + background-color: #007d00 +} + +.lime { + color: #00bf00 +} + +.lime-background { + background-color: #00fa00 +} + +.maroon { + color: #600000 +} + +.maroon-background { + background-color: #7d0000 +} + +.navy { + color: #000060 +} + +.navy-background { + background-color: #00007d +} + +.olive { + color: #606000 +} + +.olive-background { + background-color: #7d7d00 +} + +.purple { + color: #600060 +} + +.purple-background { + background-color: #7d007d +} + +.red { + color: #bf0000 +} + +.red-background { + background-color: #fa0000 +} + +.silver { + color: #909090 +} + +.silver-background { + background-color: #bcbcbc +} + +.teal { + color: #006060 +} + +.teal-background { + background-color: #007d7d +} + +.white { + color: #bfbfbf +} + +.white-background { + background-color: #fafafa +} + +.yellow { + color: #bfbf00 +} + +.yellow-background { + background-color: #fafa00 +} + +span.icon > .fa { + cursor: default +} + +.admonitionblock td.icon [class^="fa icon-"] { + font-size: 2.5em; + text-shadow: 1px 1px 2px rgba(0, 0, 0, .5); + cursor: default +} + +.admonitionblock td.icon .icon-note:before { + content: "\f05a"; + color: #19407c +} + +.admonitionblock td.icon .icon-tip:before { + content: "\f0eb"; + text-shadow: 1px 1px 2px rgba(155, 155, 0, .8); + color: #111 +} + +.admonitionblock td.icon .icon-warning:before { + content: "\f071"; + color: #bf6900 +} + +.admonitionblock td.icon .icon-caution:before { + content: "\f06d"; + color: #bf3400 +} + +.admonitionblock td.icon .icon-important:before { + content: "\f06a"; + color: #bf0000 +} + +.conum[data-value] { + display: inline-block; + color: #fff !important; + background-color: rgba(0, 0, 0, .8); + -webkit-border-radius: 100px; + border-radius: 100px; + text-align: center; + font-size: .75em; + width: 1.67em; + height: 1.67em; + line-height: 1.67em; + font-family: "Open Sans", "DejaVu Sans", sans-serif; + font-style: normal; + font-weight: bold +} + +.conum[data-value] * { + color: #fff !important +} + +.conum[data-value] + b { + display: none +} + +.conum[data-value]:after { + content: attr(data-value) +} + +pre .conum[data-value] { + position: relative; + top: -.125em +} + +b.conum * { + color: inherit !important +} + +.conum:not([data-value]):empty { + display: none +} + +h1, h2 { + letter-spacing: -.01em +} + +dt, th.tableblock, td.content { + text-rendering: optimizeLegibility +} + +p, td.content { + letter-spacing: -.01em +} + +p strong, td.content strong { + letter-spacing: -.005em +} + +p, blockquote, dt, td.content { + font-size: 1.0625rem +} + +p { + margin-bottom: 1.25rem +} + +.sidebarblock p, .sidebarblock dt, .sidebarblock td.content, p.tableblock { + font-size: 1em +} + +.exampleblock > .content { + background-color: #fffef7; + border-color: #e0e0dc; + -webkit-box-shadow: 0 1px 4px #e0e0dc; + box-shadow: 0 1px 4px #e0e0dc +} + +.print-only { + display: none !important +} + +@media print { + @page { + margin: 1.25cm .75cm + } + + * { + -webkit-box-shadow: none !important; + box-shadow: none !important; + text-shadow: none !important + } + + a { + color: inherit !important; + text-decoration: underline !important + } + + a.bare, a[href^="#"], a[href^="mailto:"] { + text-decoration: none !important + } + + a[href^="http:"]:not(.bare):after, a[href^="https:"]:not(.bare):after { + content: "(" attr(href) ")"; + display: inline-block; + font-size: .875em; + padding-left: .25em + } + + abbr[title]:after { + content: " (" attr(title) ")" + } + + pre, blockquote, tr, img { + page-break-inside: avoid + } + + thead { + display: table-header-group + } + + img { + max-width: 100% !important + } + + p, blockquote, dt, td.content { + font-size: 1em; + orphans: 3; + widows: 3 + } + + h2, h3, #toctitle, .sidebarblock > .content > .title { + page-break-after: avoid + } + + #toc, .sidebarblock, .exampleblock > .content { + background: none !important + } + + #toc { + border-bottom: 1px solid #ddddd8 !important; + padding-bottom: 0 !important + } + + .sect1 { + padding-bottom: 0 !important + } + + .sect1 + .sect1 { + border: 0 !important + } + + #header > h1:first-child { + margin-top: 1.25rem + } + + body.book #header { + text-align: center + } + + body.book #header > h1:first-child { + border: 0 !important; + margin: 2.5em 0 1em 0 + } + + body.book #header .details { + border: 0 !important; + display: block; + padding: 0 !important + } + + body.book #header .details span:first-child { + margin-left: 0 !important + } + + body.book #header .details br { + display: block + } + + body.book #header .details br + span:before { + content: none !important + } + + body.book #toc { + border: 0 !important; + text-align: left !important; + padding: 0 !important; + margin: 0 !important + } + + body.book #toc, body.book #preamble, body.book h1.sect0, body.book .sect1 > h2 { + page-break-before: always + } + + .listingblock code[data-lang]:before { + display: block + } + + #footer { + background: none !important; + padding: 0 .9375em + } + + #footer-text { + color: rgba(0, 0, 0, .6) !important; + font-size: .9em + } + + .hide-on-print { + display: none !important + } + + .print-only { + display: block !important + } + + .hide-for-print { + display: none !important + } + + .show-for-print { + display: inherit !important + } +} diff --git a/docs/pom.xml b/docs/pom.xml index 3896e177..3f15becc 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/mvnw b/mvnw index 25f750cb..5551fde8 100755 --- a/mvnw +++ b/mvnw @@ -54,38 +54,16 @@ case "`uname`" in CYGWIN*) cygwin=true ;; MINGW*) mingw=true;; Darwin*) darwin=true - # - # Look for the Apple JDKs first to preserve the existing behaviour, and then look - # for the new JDKs provided by Oracle. - # - if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then - # - # Apple JDKs - # - export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then - # - # Apple JDKs - # - export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then - # - # Oracle JDKs - # - export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then - # - # Apple JDKs - # - export JAVA_HOME=`/usr/libexec/java_home` - fi - ;; + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; esac if [ -z "$JAVA_HOME" ] ; then @@ -130,7 +108,7 @@ if $cygwin ; then CLASSPATH=`cygpath --path --unix "$CLASSPATH"` fi -# For Migwn, ensure paths are in UNIX format before anything is touched +# For Mingw, ensure paths are in UNIX format before anything is touched if $mingw ; then [ -n "$M2_HOME" ] && M2_HOME="`(cd "$M2_HOME"; pwd)`" @@ -184,27 +162,28 @@ fi CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` -fi - # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { - local basedir=$(pwd) - local wdir=$(pwd) + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" while [ "$wdir" != '/' ] ; do if [ -d "$wdir"/.mvn ] ; then basedir=$wdir break fi - wdir=$(cd "$wdir/.."; pwd) + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround done echo "${basedir}" } @@ -216,38 +195,92 @@ concat_lines() { fi } -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -echo "Running version check" -VERSION=$( sed '\!//' -e 's!.*$!!' ) -echo "The found version is [${VERSION}]" - -if echo $VERSION | egrep -q 'M|RC'; then - echo Activating \"milestone\" profile for version=\"$VERSION\" - echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pmilestone" -else - echo Deactivating \"milestone\" profile for version=\"$VERSION\" - echo $MAVEN_ARGS | grep -q milestone && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pmilestone//') -fi - -if echo $VERSION | egrep -q 'RELEASE'; then - echo Activating \"central\" profile for version=\"$VERSION\" - echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pcentral" -else - echo Deactivating \"central\" profile for version=\"$VERSION\" - echo $MAVEN_ARGS | grep -q central && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pcentral//') -fi - exec "$JAVACMD" \ $MAVEN_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} ${MAVEN_ARGS} "$@" + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100755 index 00000000..48363fa6 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,161 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" +FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index 151e33d6..88334b85 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 @@ -25,14 +25,24 @@ 2.1.1.BUILD-SNAPSHOT 2.1.1.BUILD-SNAPSHOT 1.0.3.RELEASE - 2.1.1.BUILD-SNAPSHOT + 2.1.1.BUILD-SNAPSHOT + Fishtown.BUILD-SNAPSHOT + + true + true + + true + https://github.com/spring-cloud/spring-cloud-consul - scm:git:git://github.com/spring-cloud/spring-cloud-consul.git - scm:git:ssh://git@github.com/spring-cloud/spring-cloud-consul.git + scm:git:git://github.com/spring-cloud/spring-cloud-consul.git + + + scm:git:ssh://git@github.com/spring-cloud/spring-cloud-consul.git + HEAD @@ -62,9 +72,26 @@ 1.8 + + io.spring.javaformat + spring-javaformat-maven-plugin + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + + diff --git a/scripts/build.sh b/scripts/build.sh index 47399467..9da481d1 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,5 +1,6 @@ #!/bin/bash +trap 'pkill -9 consul; EXIT' 0 ./src/main/bash/travis_install_consul.sh ./src/test/bash/travis_run_consul.sh ./mvnw clean install -B -Pdocs ${@} diff --git a/spring-cloud-consul-binder/pom.xml b/spring-cloud-consul-binder/pom.xml index 5d0b7250..5b18eb3e 100644 --- a/spring-cloud-consul-binder/pom.xml +++ b/spring-cloud-consul-binder/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulBinder.java b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulBinder.java index b18321b4..341fb30f 100644 --- a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulBinder.java +++ b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulBinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,8 @@ import org.springframework.util.Assert; /** * @author Spencer Gibb */ -public class ConsulBinder extends AbstractBinder { +public class ConsulBinder + extends AbstractBinder { private static final String BEAN_NAME_TEMPLATE = "outbound.%s"; @@ -40,8 +41,10 @@ public class ConsulBinder extends AbstractBinder doBindConsumer(String name, String group, MessageChannel inputChannel, ConsumerProperties properties) { - ConsulInboundMessageProducer messageProducer = new ConsulInboundMessageProducer(this.eventService); + protected Binding doBindConsumer(String name, String group, + MessageChannel inputChannel, ConsumerProperties properties) { + ConsulInboundMessageProducer messageProducer = new ConsulInboundMessageProducer( + this.eventService); messageProducer.setOutputChannel(inputChannel); messageProducer.setBeanFactory(this.getBeanFactory()); messageProducer.afterPropertiesSet(); @@ -51,13 +54,16 @@ public class ConsulBinder extends AbstractBinder doBindProducer(String name, MessageChannel channel, ProducerProperties properties) { + protected Binding doBindProducer(String name, MessageChannel channel, + ProducerProperties properties) { Assert.isInstanceOf(SubscribableChannel.class, channel); - logger.debug("Binding Consul client to eventName " + name); - ConsulSendingHandler sendingHandler = new ConsulSendingHandler(this.eventService.getConsulClient(), name); + this.logger.debug("Binding Consul client to eventName " + name); + ConsulSendingHandler sendingHandler = new ConsulSendingHandler( + this.eventService.getConsulClient(), name); - EventDrivenConsumer consumer = new EventDrivenConsumer((SubscribableChannel) channel, sendingHandler); + EventDrivenConsumer consumer = new EventDrivenConsumer( + (SubscribableChannel) channel, sendingHandler); consumer.setBeanFactory(getBeanFactory()); consumer.setBeanName(String.format(BEAN_NAME_TEMPLATE, name)); consumer.afterPropertiesSet(); @@ -65,4 +71,5 @@ public class ConsulBinder extends AbstractBinder(name, null, channel, consumer); } + } diff --git a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulInboundMessageProducer.java b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulInboundMessageProducer.java index 80050f33..ba70a30b 100644 --- a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulInboundMessageProducer.java +++ b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulInboundMessageProducer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,6 @@ package org.springframework.cloud.consul.binder; -import static org.springframework.util.Base64Utils.decodeFromString; - import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -25,24 +23,31 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import com.ecwid.consul.v1.OperationException; +import com.ecwid.consul.v1.event.model.Event; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.integration.endpoint.MessageProducerSupport; -import com.ecwid.consul.v1.event.model.Event; +import static org.springframework.util.Base64Utils.decodeFromString; /** * Adapter that receives Messages from Consul Events, converts them into Spring * Integration Messages, and sends the results to a Message Channel. + * * @author Spencer Gibb */ public class ConsulInboundMessageProducer extends MessageProducerSupport { - protected static final Log logger = LogFactory.getLog(ConsulInboundMessageProducer.class); + protected static final Log logger = LogFactory + .getLog(ConsulInboundMessageProducer.class); + + private final ScheduledExecutorService scheduler; + + private final Runnable eventsRunnable; private EventService eventService; - private final ScheduledExecutorService scheduler; - private final Runnable eventsRunnable; + private ScheduledFuture eventsHandle; public ConsulInboundMessageProducer(EventService eventService) { @@ -75,8 +80,9 @@ public class ConsulInboundMessageProducer extends MessageProducerSupport { @Override protected void doStart() { - //TODO: make configurable - eventsHandle = this.scheduler.scheduleWithFixedDelay(eventsRunnable, 500, 500, TimeUnit.MILLISECONDS); + // TODO: make configurable + this.eventsHandle = this.scheduler.scheduleWithFixedDelay(this.eventsRunnable, + 500, 500, TimeUnit.MILLISECONDS); } @Override @@ -90,20 +96,22 @@ public class ConsulInboundMessageProducer extends MessageProducerSupport { // @Scheduled(fixedDelayString = "${spring.cloud.consul.binder.eventDelay:30000}") public void getEvents() { try { - List events = eventService.watch(); + List events = this.eventService.watch(); for (Event event : events) { // Map headers = new HashMap<>(); // headers.put(MessageHeaders.REPLY_CHANNEL, outputChannel.) String decoded = new String(decodeFromString(event.getPayload())); sendMessage(getMessageBuilderFactory().withPayload(decoded) - // TODO: support headers + // TODO: support headers .build()); } - } catch (OperationException e) { + } + catch (OperationException e) { if (logger.isErrorEnabled()) { logger.error("Error getting consul events: " + e); } - } catch (Exception e) { + } + catch (Exception e) { if (logger.isErrorEnabled()) { logger.error("Error getting consul events: " + e.getMessage()); } @@ -112,4 +120,5 @@ public class ConsulInboundMessageProducer extends MessageProducerSupport { } } } + } diff --git a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulSendingHandler.java b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulSendingHandler.java index f18fe60c..fd51dc3a 100644 --- a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulSendingHandler.java +++ b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/ConsulSendingHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,23 +16,24 @@ package org.springframework.cloud.consul.binder; -import org.springframework.integration.handler.AbstractMessageHandler; -import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; -import org.springframework.messaging.Message; - import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.QueryParams; import com.ecwid.consul.v1.Response; import com.ecwid.consul.v1.event.model.Event; import com.ecwid.consul.v1.event.model.EventParams; +import org.springframework.integration.handler.AbstractMessageHandler; +import org.springframework.messaging.Message; + /** - * Adapter that converts and sends Messages as Consul events + * Adapter that converts and sends Messages as Consul events. + * * @author Spencer Gibb */ public class ConsulSendingHandler extends AbstractMessageHandler { private final ConsulClient consul; + private final String eventName; public ConsulSendingHandler(ConsulClient consul, String eventName) { @@ -42,16 +43,17 @@ public class ConsulSendingHandler extends AbstractMessageHandler { @Override protected void handleMessageInternal(Message message) throws Exception { - if (logger.isTraceEnabled()) { - logger.trace("Publishing message" + message); + if (this.logger.isTraceEnabled()) { + this.logger.trace("Publishing message" + message); } Object payload = message.getPayload(); // TODO: support headers // TODO: support consul event filters: NodeFilter, ServiceFilter, TagFilter - Response event = consul.eventFire(this.eventName, (String) payload, + Response event = this.consul.eventFire(this.eventName, (String) payload, new EventParams(), QueryParams.DEFAULT); // TODO: return event? // return null; } + } diff --git a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/EventService.java b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/EventService.java index 7502c480..c6cf51f8 100644 --- a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/EventService.java +++ b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/EventService.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,6 @@ import java.util.concurrent.atomic.AtomicReference; import javax.annotation.PostConstruct; -import org.springframework.cloud.consul.binder.config.ConsulBinderProperties; - import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.QueryParams; import com.ecwid.consul.v1.Response; @@ -30,6 +28,8 @@ import com.ecwid.consul.v1.event.model.Event; import com.ecwid.consul.v1.event.model.EventParams; import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.cloud.consul.binder.config.ConsulBinderProperties; + /** * @author Spencer Gibb */ @@ -43,14 +43,15 @@ public class EventService { private AtomicReference lastIndex = new AtomicReference<>(); - public EventService(ConsulBinderProperties properties, ConsulClient consul, ObjectMapper objectMapper) { + public EventService(ConsulBinderProperties properties, ConsulClient consul, + ObjectMapper objectMapper) { this.properties = properties; this.consul = consul; this.objectMapper = objectMapper; } public ConsulClient getConsulClient() { - return consul; + return this.consul; } @PostConstruct @@ -58,25 +59,25 @@ public class EventService { setLastIndex(getEventsResponse()); } + public Long getLastIndex() { + return this.lastIndex.get(); + } + private void setLastIndex(Response response) { Long consulIndex = response.getConsulIndex(); if (consulIndex != null) { - lastIndex.set(response.getConsulIndex()); + this.lastIndex.set(response.getConsulIndex()); } } - public Long getLastIndex() { - return lastIndex.get(); - } - public Event fire(String name, String payload) { - Response response = consul.eventFire(name, payload, new EventParams(), + Response response = this.consul.eventFire(name, payload, new EventParams(), QueryParams.DEFAULT); return response.getValue(); } public Response> getEventsResponse() { - return consul.eventList(QueryParams.DEFAULT); + return this.consul.eventList(QueryParams.DEFAULT); } public List getEvents() { @@ -88,7 +89,7 @@ public class EventService { } public List watch() { - return watch(lastIndex.get()); + return watch(this.lastIndex.get()); } public List watch(Long lastIndex) { @@ -98,10 +99,11 @@ public class EventService { index = lastIndex; } int eventTimeout = 5; - if (properties != null) { - eventTimeout = properties.getEventTimeout(); + if (this.properties != null) { + eventTimeout = this.properties.getEventTimeout(); } - Response> watch = consul.eventList(new QueryParams(eventTimeout, index)); + Response> watch = this.consul + .eventList(new QueryParams(eventTimeout, index)); return filterEvents(readEvents(watch), lastIndex); } @@ -111,7 +113,10 @@ public class EventService { } /** - * from https://github.com/hashicorp/consul/blob/master/watch/funcs.go#L169-L194 + * from https://github.com/hashicorp/consul/blob/master/watch/funcs.go#L169-L194 . + * @param toFilter events to filter + * @param lastIndex last index to pick from the list of events + * @return filtered list of events */ protected List filterEvents(List toFilter, Long lastIndex) { List events = toFilter; diff --git a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/config/ConsulBinderConfiguration.java b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/config/ConsulBinderConfiguration.java index d4c95789..98c34d2d 100644 --- a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/config/ConsulBinderConfiguration.java +++ b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/config/ConsulBinderConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,13 @@ package org.springframework.cloud.consul.binder.config; +import com.ecwid.consul.v1.ConsulClient; +import com.fasterxml.jackson.databind.ObjectMapper; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.consul.ConditionalOnConsulEnabled; import org.springframework.cloud.consul.binder.ConsulBinder; import org.springframework.cloud.consul.binder.EventService; @@ -29,9 +31,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import com.ecwid.consul.v1.ConsulClient; -import com.fasterxml.jackson.databind.ObjectMapper; - /** * Configures the Consul binder. * @@ -42,7 +41,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; @Import({ PropertyPlaceholderAutoConfiguration.class }) @ConditionalOnConsulEnabled @ConditionalOnProperty(name = "spring.cloud.consul.binder.enabled", matchIfMissing = true) -//FIXME: boot 2.0.0 @EnableConfigurationProperties({ConsulBinderProperties.class}) +// FIXME: boot 2.0.0 @EnableConfigurationProperties({ConsulBinderProperties.class}) public class ConsulBinderConfiguration { // @Autowired @@ -54,7 +53,8 @@ public class ConsulBinderConfiguration { @Bean @ConditionalOnMissingBean public EventService eventService(ConsulClient consulClient) { - return new EventService(null/*consulBinderProperties*/, consulClient, objectMapper); + return new EventService(null/* consulBinderProperties */, consulClient, + this.objectMapper); } @Bean @@ -63,5 +63,6 @@ public class ConsulBinderConfiguration { return new ConsulBinder(eventService); } - //TODO: create consul client if needed + // TODO: create consul client if needed + } diff --git a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/config/ConsulBinderProperties.java b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/config/ConsulBinderProperties.java index ee5988f3..d502acd5 100644 --- a/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/config/ConsulBinderProperties.java +++ b/spring-cloud-consul-binder/src/main/java/org/springframework/cloud/consul/binder/config/ConsulBinderProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.springframework.core.style.ToStringCreator; */ @ConfigurationProperties("spring.cloud.stream.consul.binder") public class ConsulBinderProperties { + private int eventTimeout = 5; public ConsulBinderProperties() { @@ -39,8 +40,8 @@ public class ConsulBinderProperties { @Override public String toString() { - return new ToStringCreator(this) - .append("eventTimeout", eventTimeout) + return new ToStringCreator(this).append("eventTimeout", this.eventTimeout) .toString(); } + } diff --git a/spring-cloud-consul-binder/src/main/resources/META-INF/spring-cloud-stream/consul-binder.properties b/spring-cloud-consul-binder/src/main/resources/META-INF/spring-cloud-stream/consul-binder.properties index db28478f..a912c091 100644 --- a/spring-cloud-consul-binder/src/main/resources/META-INF/spring-cloud-stream/consul-binder.properties +++ b/spring-cloud-consul-binder/src/main/resources/META-INF/spring-cloud-stream/consul-binder.properties @@ -13,6 +13,5 @@ # See the License for the specific language governing permissions and # limitations under the License. # - spring.cloud.stream.binder.consul.default.host=localhost spring.cloud.stream.binder.consul.default.port=8500 diff --git a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulBinderApplicationTests.java b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulBinderApplicationTests.java index 7f20bf52..9da69779 100644 --- a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulBinderApplicationTests.java +++ b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulBinderApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,14 @@ package org.springframework.cloud.consul.binder; import java.util.concurrent.TimeUnit; +import com.ecwid.consul.v1.ConsulClient; +import com.github.tomakehurst.wiremock.junit.WireMockRule; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -36,19 +39,17 @@ import org.springframework.messaging.support.MessageBuilder; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.github.tomakehurst.wiremock.junit.WireMockRule; - import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.put; import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD; + /** * @author Spencer Gibb */ @@ -56,33 +57,35 @@ import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER @SpringBootTest(classes = ConsulBinderApplicationTests.Application.class) @DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) public class ConsulBinderApplicationTests { - @Autowired - private Events events; @Rule public final WireMockRule wireMock = new WireMockRule(18500); + @Autowired + private Events events; + @Before public void setUp() throws Exception { - wireMock.stubFor(put(urlPathMatching("/v1/event/fire/purchases")) + this.wireMock.stubFor(put(urlPathMatching("/v1/event/fire/purchases")) .willReturn(aResponse().withStatus(200))); - /*wireMock.stubFor(get(urlPathMatching("/v1/event/list")) - .willReturn(aResponse().withBody("[]") - .withStatus(200) - .withHeader("X-Consul-Index", "1")));*/ + /* + * wireMock.stubFor(get(urlPathMatching("/v1/event/list")) + * .willReturn(aResponse().withBody("[]") .withStatus(200) + * .withHeader("X-Consul-Index", "1"))); + */ } @Test - @Ignore //FIXME: 2.0.0 need stream fix + @Ignore // FIXME: 2.0.0 need stream fix public void shouldInitializeConsulSource() { - assertNotNull(events); + assertThat(this.events).isNotNull(); } @Test - @Ignore //FIXME: 2.0.0 need stream fix + @Ignore // FIXME: 2.0.0 need stream fix public void shouldPublishTextConsulMessage() { // given @@ -90,7 +93,7 @@ public class ConsulBinderApplicationTests { .build(); // when - events.purchases().send(message); + this.events.purchases().send(message); // then await().atMost(1, TimeUnit.SECONDS); @@ -101,12 +104,14 @@ public class ConsulBinderApplicationTests { @Output MessageChannel purchases(); + } @Configuration @EnableAutoConfiguration @EnableBinding(Events.class) public static class Application { + @Bean public ConsulClient consulClient() { return new ConsulClient("localhost", 18500); @@ -118,5 +123,7 @@ public class ConsulBinderApplicationTests { when(eventService.getConsulClient()).thenReturn(consulClient); return eventService; } + } + } diff --git a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulBinderTests.java b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulBinderTests.java index 1f434f1d..8997c67f 100644 --- a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulBinderTests.java +++ b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulBinderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.cloud.consul.binder.test.consumer.TestConsumer; import org.springframework.cloud.consul.binder.test.producer.TestProducer; import org.springframework.cloud.deployer.spi.app.AppDeployer; @@ -40,8 +41,7 @@ import org.springframework.util.SocketUtils; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * Tests for {@link org.springframework.cloud.consul.binder.ConsulBinder}. @@ -49,12 +49,6 @@ import static org.junit.Assert.assertTrue; * @author Spencer Gibb */ public class ConsulBinderTests { - private static final Logger logger = LoggerFactory.getLogger(ConsulBinderTests.class); - - /** - * Timeout value in milliseconds for operations to complete. - */ - private static final long TIMEOUT = 30000; /** * Payload of test message. @@ -66,6 +60,13 @@ public class ConsulBinderTests { */ public static final String BINDING_NAME = "test"; + private static final Logger logger = LoggerFactory.getLogger(ConsulBinderTests.class); + + /** + * Timeout value in milliseconds for operations to complete. + */ + private static final long TIMEOUT = 30000; + /** * Deployer to launch producer and consumer test applications. */ @@ -76,7 +77,6 @@ public class ConsulBinderTests { */ private final RestTemplate restTemplate = new RestTemplate(); - public ConsulBinderTests() { LocalDeployerProperties properties = new LocalDeployerProperties(); properties.setDeleteFilesOnExit(false); @@ -85,43 +85,38 @@ public class ConsulBinderTests { /** * Test basic message sending functionality. - * - * @throws Exception + * @throws InterruptedException when waiting for message was interrupted */ @Test - @Ignore //FIXME: 2.0.0 need stream fix - public void testMessageSendReceive() throws Exception { + @Ignore // FIXME: 2.0.0 need stream fix + public void testMessageSendReceive() throws InterruptedException { testMessageSendReceive(null); } /** * Test usage of partition selector. - * * @throws Exception */ - /*@Test - public void testPartitionedMessageSendReceive() throws Exception { - testMessageSendReceive(null, true); - }*/ + /* + * @Test public void testPartitionedMessageSendReceive() throws Exception { + * testMessageSendReceive(null, true); } + */ /** * Test consumer group functionality. - * * @throws Exception */ - /*@Test - public void testMessageSendReceiveConsumerGroups() throws Exception { - testMessageSendReceive(new String[]{"a", "b"}, false); - }*/ + /* + * @Test public void testMessageSendReceiveConsumerGroups() throws Exception { + * testMessageSendReceive(new String[]{"a", "b"}, false); } + */ /** * Test message sending functionality. - * * @param groups consumer groups; may be {@code null} - * @param partitioned if true, execute test with a partition selector - * @throws Exception + * @throws InterruptedException when waiting for message was interrupted */ - private void testMessageSendReceive(String[] groups) throws Exception { + private void testMessageSendReceive(String[] groups) throws InterruptedException { Set consumers = null; AppId producer = null; @@ -130,7 +125,7 @@ public class ConsulBinderTests { producer = launchProducer(); for (AppId consumer : consumers) { - assertEquals(MESSAGE_PAYLOAD, waitForMessage(consumer.port)); + assertThat(waitForMessage(consumer.port)).isEqualTo(MESSAGE_PAYLOAD); } } finally { @@ -146,12 +141,11 @@ public class ConsulBinderTests { } /** - * Launch one or more consumers based on the number of consumer groups. - * Blocks execution until the consumers are bound. - * + * Launch one or more consumers based on the number of consumer groups. Blocks + * execution until the consumers are bound. * @param groups consumer groups; may be {@code null} * @return a set of {@link AppId}s for the consumers - * @throws InterruptedException + * @throws InterruptedException when waiting for message was interrupted */ private Set launchConsumers(String[] groups) throws InterruptedException { Set consumers = new HashSet<>(); @@ -170,7 +164,9 @@ public class ConsulBinderTests { if (groups != null) { args.add(String.format("--group=%s", groups[i])); } - consumers.add(new AppId(launchApplication(TestConsumer.class, appProperties, args), consumerPort)); + consumers.add( + new AppId(launchApplication(TestConsumer.class, appProperties, args), + consumerPort)); } for (AppId app : consumers) { waitForConsumer(app.port); @@ -181,7 +177,6 @@ public class ConsulBinderTests { /** * Launch a producer that publishes a test message. - * * @return {@link AppId} for producer */ private AppId launchProducer() { @@ -196,16 +191,16 @@ public class ConsulBinderTests { args.add(String.format("--partitioned=%b", false)); args.add("--debug"); - return new AppId(launchApplication(TestProducer.class, appProperties, args), producerPort); + return new AppId(launchApplication(TestProducer.class, appProperties, args), + producerPort); } /** * Block the executing thread until the consumer is bound. - * * @param port server port of the consumer application * @throws InterruptedException if the thread is interrupted - * @throws AssertionError if the consumer is not bound after - * {@value #TIMEOUT} milliseconds + * @throws AssertionError if the consumer is not bound after {@value #TIMEOUT} + * milliseconds */ private void waitForConsumer(int port) throws InterruptedException { long start = System.currentTimeMillis(); @@ -217,18 +212,17 @@ public class ConsulBinderTests { Thread.sleep(1000); } } - assertTrue("Consumer not bound", isConsumerBound(port)); + assertThat(isConsumerBound(port)).as("Consumer not bound").isTrue(); } /** * Return {@code true} if the consumer at the provided port is bound. - * * @param port http port for consumer * @return true if consumer is bound */ private boolean isConsumerBound(int port) { try { - return restTemplate.getForObject( + return this.restTemplate.getForObject( String.format("http://localhost:%d/is-bound", port), Boolean.class); } catch (ResourceAccessException e) { @@ -239,15 +233,14 @@ public class ConsulBinderTests { /** * Return the most recent payload message a consumer received. - * * @param port http port for consumer - * @return the most recent payload message a consumer received; - * may be {@code null} + * @return the most recent payload message a consumer received; may be {@code null} */ private String getConsumerMessagePayload(int port) { try { - return restTemplate.getForObject( - String.format("http://localhost:%d/message-payload", port), String.class); + return this.restTemplate.getForObject( + String.format("http://localhost:%d/message-payload", port), + String.class); } catch (ResourceAccessException e) { logger.debug("getConsumerMessagePayload", e); @@ -257,13 +250,12 @@ public class ConsulBinderTests { /** * Return {@code true} if the producer made use of a custom partition selector. - * * @param port http port for producer * @return true if the producer used a custom partition selector */ - private boolean partitionSelectorUsed(int port) throws InterruptedException { + private boolean partitionSelectorUsed(int port) { try { - return restTemplate.getForObject( + return this.restTemplate.getForObject( String.format("http://localhost:%d/partition-strategy-invoked", port), Boolean.class); } @@ -274,9 +266,8 @@ public class ConsulBinderTests { } /** - * Block the executing thread until a message is received by the - * consumer application, or until {@value #TIMEOUT} milliseconds elapses. - * + * Block the executing thread until a message is received by the consumer application, + * or until {@value #TIMEOUT} milliseconds elapses. * @param port server port of the consumer application * @return the message payload that was received * @throws InterruptedException if the thread is interrupted @@ -298,29 +289,31 @@ public class ConsulBinderTests { /** * Launch an application in a separate JVM. - * * @param clz the main class to launch * @param properties the properties to pass to the application * @param args the command line arguments for the application * @return a string identifier for the application */ - private String launchApplication(Class clz, Map properties, List args) { - Resource resource = new UrlResource(clz.getProtectionDomain().getCodeSource().getLocation()); + private String launchApplication(Class clz, Map properties, + List args) { + Resource resource = new UrlResource( + clz.getProtectionDomain().getCodeSource().getLocation()); properties.put(AppDeployer.GROUP_PROPERTY_KEY, "test-group"); properties.put("main", clz.getName()); properties.put("classpath", System.getProperty("java.class.path")); - String appName = String.format("%s-%s", clz.getSimpleName(), properties.get("server.port")); + String appName = String.format("%s-%s", clz.getSimpleName(), + properties.get("server.port")); AppDefinition definition = new AppDefinition(appName, properties); - AppDeploymentRequest request = new AppDeploymentRequest(definition, resource, properties, args); + AppDeploymentRequest request = new AppDeploymentRequest(definition, resource, + properties, args); return this.deployer.deploy(request); } /** * Shut down the application with the provided id. - * * @param id id of application to shut down */ private void shutdownApplication(String id) { @@ -331,7 +324,6 @@ public class ConsulBinderTests { /** * Instantiates a new local app deployer. - * * @param properties the properties */ ClasspathDeployer(LocalDeployerProperties properties) { @@ -340,12 +332,12 @@ public class ConsulBinderTests { /** * Builds the jar execution command. - * * @param jarPath the jar path * @param request the request * @return the string[] */ - protected String[] buildJarExecutionCommand(String jarPath, AppDeploymentRequest request) { + protected String[] buildJarExecutionCommand(String jarPath, + AppDeploymentRequest request) { ArrayList commands = new ArrayList<>(); commands.add(super.getLocalDeployerProperties().getJavaCmd()); @@ -356,14 +348,16 @@ public class ConsulBinderTests { return commands.toArray(new String[commands.size()]); } - } + } /** * String identification and http port for a launched application. */ private static class AppId { + final String id; + final int port; AppId(String id, int port) { @@ -381,15 +375,16 @@ public class ConsulBinderTests { } AppId appId = (AppId) o; - return port == appId.port && id.equals(appId.id); + return this.port == appId.port && this.id.equals(appId.id); } @Override public int hashCode() { - int result = id.hashCode(); - result = 31 * result + port; + int result = this.id.hashCode(); + result = 31 * result + this.port; return result; } + } } diff --git a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulInboundMessageProducerTests.java b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulInboundMessageProducerTests.java index b9d78d0d..6a6f1917 100644 --- a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulInboundMessageProducerTests.java +++ b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/ConsulInboundMessageProducerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,10 @@ package org.springframework.cloud.consul.binder; +import com.ecwid.consul.v1.OperationException; import org.junit.Test; -import com.ecwid.consul.v1.OperationException; - -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -34,15 +33,16 @@ public class ConsulInboundMessageProducerTests { EventService eventService = mock(EventService.class); when(eventService.watch()).thenThrow(new OperationException(500, "error", "")); - ConsulInboundMessageProducer producer = new ConsulInboundMessageProducer(eventService); + ConsulInboundMessageProducer producer = new ConsulInboundMessageProducer( + eventService); try { producer.getEvents(); - } catch (Exception e) { - fail("ConsulInboundMessageProducer threw unexpected exception: "+e); + } + catch (Exception e) { + fail("ConsulInboundMessageProducer threw unexpected exception: " + e); } } - } diff --git a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/config/ConsulBinderConfigurationTests.java b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/config/ConsulBinderConfigurationTests.java index b6ad2380..9b377f56 100644 --- a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/config/ConsulBinderConfigurationTests.java +++ b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/config/ConsulBinderConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.stream.annotation.EnableBinding; @@ -38,31 +39,33 @@ public class ConsulBinderConfigurationTests { public ExpectedException exception = ExpectedException.none(); @Test - @Ignore //FIXME 2.0.0 need stream fix + @Ignore // FIXME 2.0.0 need stream fix public void consulBinderDisabledWorks() { this.exception.expectMessage(containsString("no proper implementation found")); new SpringApplicationBuilder(Application.class) - .properties("spring.cloud.consul.binder.enabled=false") - .run(); + .properties("spring.cloud.consul.binder.enabled=false").run(); } @Test - @Ignore //FIXME 2.0.0 need stream fix + @Ignore // FIXME 2.0.0 need stream fix public void consulDisabledDisablesBinder() { this.exception.expectMessage(containsString("no proper implementation found")); new SpringApplicationBuilder(Application.class) - .properties("spring.cloud.consul.enabled=false") - .run(); + .properties("spring.cloud.consul.enabled=false").run(); } interface Events { + @Output MessageChannel purchases(); + } @Configuration @EnableAutoConfiguration @EnableBinding(Events.class) public static class Application { + } + } diff --git a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/test/consumer/TestConsumer.java b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/test/consumer/TestConsumer.java index 11e3a48b..5cdf5300 100644 --- a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/test/consumer/TestConsumer.java +++ b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/test/consumer/TestConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.cloud.consul.binder.test.consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; @@ -27,7 +28,6 @@ import org.springframework.cloud.consul.binder.ConsulBinder; import org.springframework.cloud.consul.binder.ConsulBinderTests; import org.springframework.cloud.consul.binder.config.ConsulBinderConfiguration; import org.springframework.cloud.stream.binder.ConsumerProperties; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.messaging.Message; @@ -39,14 +39,15 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** - * Consumer application that binds a channel to a {@link ConsulBinder} - * and stores the received message payload. + * Consumer application that binds a channel to a {@link ConsulBinder} and stores the + * received message payload. */ @RestController @Import(ConsulBinderConfiguration.class) @Configuration @EnableAutoConfiguration public class TestConsumer implements ApplicationRunner { + private static final Logger logger = LoggerFactory.getLogger(TestConsumer.class); /** @@ -64,23 +65,21 @@ public class TestConsumer implements ApplicationRunner { /** * Main method. - * * @param args if present, first arg is consumer group name - * @throws Exception */ - public static void main(String[] args) throws Exception { + public static void main(String[] args) { SpringApplication.run(TestConsumer.class, args); } @Override public void run(ApplicationArguments args) throws Exception { - logger.info("Consumer running with binder {}", binder); + logger.info("Consumer running with binder {}", this.binder); SubscribableChannel consumerChannel = new ExecutorSubscribableChannel(); consumerChannel.subscribe(new MessageHandler() { @Override public void handleMessage(Message message) throws MessagingException { - messagePayload = (String) message.getPayload(); - logger.info("Received message: {}", messagePayload); + TestConsumer.this.messagePayload = (String) message.getPayload(); + logger.info("Received message: {}", TestConsumer.this.messagePayload); } }); String group = null; @@ -89,19 +88,19 @@ public class TestConsumer implements ApplicationRunner { group = args.getOptionValues("group").get(0); } - binder.bindConsumer(ConsulBinderTests.BINDING_NAME, group, consumerChannel, + this.binder.bindConsumer(ConsulBinderTests.BINDING_NAME, group, consumerChannel, new ConsumerProperties()); - isBound = true; + this.isBound = true; } @RequestMapping("/is-bound") public boolean isBound() { - return isBound; + return this.isBound; } @RequestMapping("/message-payload") public String getMessagePayload() { - return messagePayload; + return this.messagePayload; } } diff --git a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/test/producer/TestProducer.java b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/test/producer/TestProducer.java index c3b79323..06c04f5f 100644 --- a/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/test/producer/TestProducer.java +++ b/spring-cloud-consul-binder/src/test/java/org/springframework/cloud/consul/binder/test/producer/TestProducer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.cloud.consul.binder.test.producer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; @@ -40,8 +41,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** - * Producer application that binds a channel to a {@link ConsulBinder} - * and sends a test message. + * Producer application that binds a channel to a {@link ConsulBinder} and sends a test + * message. */ @RestController @Import(ConsulBinderConfiguration.class) @@ -60,17 +61,20 @@ public class TestProducer implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { - /*if (args.containsOption("partitioned") - && Boolean.valueOf(args.getOptionValues("partitioned").get(0))) { - binder.setPartitionSelector(stubPartitionSelectorStrategy()); - }*/ + /* + * if (args.containsOption("partitioned") && + * Boolean.valueOf(args.getOptionValues("partitioned").get(0))) { + * binder.setPartitionSelector(stubPartitionSelectorStrategy()); } + */ SubscribableChannel producerChannel = producerChannel(); ProducerProperties properties = new ProducerProperties(); - properties.setPartitionKeyExpression(new SpelExpressionParser().parseExpression("payload")); - binder.bindProducer(ConsulBinderTests.BINDING_NAME, producerChannel, properties); + properties.setPartitionKeyExpression( + new SpelExpressionParser().parseExpression("payload")); + this.binder.bindProducer(ConsulBinderTests.BINDING_NAME, producerChannel, + properties); Message message = new GenericMessage<>(ConsulBinderTests.MESSAGE_PAYLOAD); - logger.info("Writing message to binder {}", binder); + logger.info("Writing message to binder {}", this.binder); producerChannel.send(message); } @@ -89,16 +93,19 @@ public class TestProducer implements ApplicationRunner { return stubPartitionSelectorStrategy().invoked; } + public static class StubPartitionSelectorStrategy + implements PartitionSelectorStrategy { - public static class StubPartitionSelectorStrategy implements PartitionSelectorStrategy { public volatile boolean invoked = false; @Override public int selectPartition(Object key, int partitionCount) { - logger.info("Selecting partition for key {}; partition count: {}", key, partitionCount); - invoked = true; + logger.info("Selecting partition for key {}; partition count: {}", key, + partitionCount); + this.invoked = true; return 1; } + } } diff --git a/spring-cloud-consul-binder/src/test/resources/application.yml b/spring-cloud-consul-binder/src/test/resources/application.yml index 7d8396c0..0c1f35a9 100644 --- a/spring-cloud-consul-binder/src/test/resources/application.yml +++ b/spring-cloud-consul-binder/src/test/resources/application.yml @@ -1,4 +1,3 @@ - spring: cloud: stream: diff --git a/spring-cloud-consul-config/pom.xml b/spring-cloud-consul-config/pom.xml index 72be559b..3186697d 100644 --- a/spring-cloud-consul-config/pom.xml +++ b/spring-cloud-consul-config/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConfigWatch.java b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConfigWatch.java index 74b854f9..471513ce 100644 --- a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConfigWatch.java +++ b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConfigWatch.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,17 +50,33 @@ public class ConfigWatch implements ApplicationEventPublisherAware, SmartLifecyc private static final Log log = LogFactory.getLog(ConfigWatch.class); private final ConsulConfigProperties properties; + private final ConsulClient consul; - private LinkedHashMap consulIndexes; + private final TaskScheduler taskScheduler; + private final AtomicBoolean running = new AtomicBoolean(false); + + private LinkedHashMap consulIndexes; + private ApplicationEventPublisher publisher; + private boolean firstTime = true; + private ScheduledFuture watchFuture; - public ConfigWatch(ConsulConfigProperties properties, ConsulClient consul, LinkedHashMap initialIndexes) { + public ConfigWatch(ConsulConfigProperties properties, ConsulClient consul, + LinkedHashMap initialIndexes) { this(properties, consul, initialIndexes, getTaskScheduler()); - } + } + + public ConfigWatch(ConsulConfigProperties properties, ConsulClient consul, + LinkedHashMap initialIndexes, TaskScheduler taskScheduler) { + this.properties = properties; + this.consul = consul; + this.consulIndexes = new LinkedHashMap<>(initialIndexes); + this.taskScheduler = taskScheduler; + } private static ThreadPoolTaskScheduler getTaskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); @@ -68,14 +84,6 @@ public class ConfigWatch implements ApplicationEventPublisherAware, SmartLifecyc return taskScheduler; } - public ConfigWatch(ConsulConfigProperties properties, ConsulClient consul, LinkedHashMap initialIndexes, - TaskScheduler taskScheduler) { - this.properties = properties; - this.consul = consul; - this.consulIndexes = new LinkedHashMap<>(initialIndexes); - this.taskScheduler = taskScheduler; - } - @Override public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; @@ -84,8 +92,8 @@ public class ConfigWatch implements ApplicationEventPublisherAware, SmartLifecyc @Override public void start() { if (this.running.compareAndSet(false, true)) { - this.watchFuture = this.taskScheduler.scheduleWithFixedDelay(this::watchConfigKeyValues, - this.properties.getWatch().getDelay()); + this.watchFuture = this.taskScheduler.scheduleWithFixedDelay( + this::watchConfigKeyValues, this.properties.getWatch().getDelay()); } } @@ -117,13 +125,14 @@ public class ConfigWatch implements ApplicationEventPublisherAware, SmartLifecyc return this.running.get(); } - @Timed(value ="consul.watch-config-keys") + @Timed("consul.watch-config-keys") public void watchConfigKeyValues() { if (this.running.get()) { for (String context : this.consulIndexes.keySet()) { - // turn the context into a Consul folder path (unless our config format are FILES) - if (properties.getFormat() != FILES && !context.endsWith("/")) { + // turn the context into a Consul folder path (unless our config format + // are FILES) + if (this.properties.getFormat() != FILES && !context.endsWith("/")) { context = context + "/"; } @@ -133,63 +142,85 @@ public class ConfigWatch implements ApplicationEventPublisherAware, SmartLifecyc currentIndex = -1L; } - log.trace("watching consul for context '"+context+"' with index "+ currentIndex); + log.trace("watching consul for context '" + context + "' with index " + + currentIndex); // use the consul ACL token if found - String aclToken = properties.getAclToken(); + String aclToken = this.properties.getAclToken(); if (StringUtils.isEmpty(aclToken)) { - aclToken = null; + aclToken = null; } - Response> response = this.consul.getKVValues(context, aclToken, + Response> response = this.consul.getKVValues(context, + aclToken, new QueryParams(this.properties.getWatch().getWaitTime(), currentIndex)); - // if response.value == null, response was a 404, otherwise it was a 200 + // if response.value == null, response was a 404, otherwise it was a + // 200 // reducing churn if there wasn't anything if (response.getValue() != null && !response.getValue().isEmpty()) { Long newIndex = response.getConsulIndex(); if (newIndex != null && !newIndex.equals(currentIndex)) { - // don't publish the same index again, don't publish the first time (-1) so index can be primed - if (!this.consulIndexes.containsValue(newIndex) && !currentIndex.equals(-1L)) { - log.trace("Context "+context + " has new index " + newIndex); - RefreshEventData data = new RefreshEventData(context, currentIndex, newIndex); - this.publisher.publishEvent(new RefreshEvent(this, data, data.toString())); - } else if (log.isTraceEnabled()) { - log.trace("Event for index already published for context "+context); + // don't publish the same index again, don't publish the first + // time (-1) so index can be primed + if (!this.consulIndexes.containsValue(newIndex) + && !currentIndex.equals(-1L)) { + log.trace("Context " + context + " has new index " + + newIndex); + RefreshEventData data = new RefreshEventData(context, + currentIndex, newIndex); + this.publisher.publishEvent( + new RefreshEvent(this, data, data.toString())); + } + else if (log.isTraceEnabled()) { + log.trace("Event for index already published for context " + + context); } this.consulIndexes.put(context, newIndex); - } else if (log.isTraceEnabled()) { - log.trace("Same index for context "+context); } - } else if (log.isTraceEnabled()) { - log.trace("No value for context "+context); + else if (log.isTraceEnabled()) { + log.trace("Same index for context " + context); + } + } + else if (log.isTraceEnabled()) { + log.trace("No value for context " + context); } - } catch (Exception e) { + } + catch (Exception e) { // only fail fast on the initial query, otherwise just log the error - if (firstTime && this.properties.isFailFast()) { - log.error("Fail fast is set and there was an error reading configuration from consul."); + if (this.firstTime && this.properties.isFailFast()) { + log.error( + "Fail fast is set and there was an error reading configuration from consul."); ReflectionUtils.rethrowRuntimeException(e); - } else if (log.isTraceEnabled()) { - log.trace("Error querying consul Key/Values for context '" + context + "'", e); - } else if (log.isWarnEnabled()) { - // simplified one line log message in the event of an agent failure - log.warn("Error querying consul Key/Values for context '" + context + "'. Message: " + e.getMessage()); + } + else if (log.isTraceEnabled()) { + log.trace("Error querying consul Key/Values for context '" + + context + "'", e); + } + else if (log.isWarnEnabled()) { + // simplified one line log message in the event of an agent + // failure + log.warn("Error querying consul Key/Values for context '" + + context + "'. Message: " + e.getMessage()); } } } } - firstTime = false; + this.firstTime = false; } static class RefreshEventData { + private final String context; + private final Long prevIndex; + private final Long newIndex; - public RefreshEventData(String context, Long prevIndex, Long newIndex) { + RefreshEventData(String context, Long prevIndex, Long newIndex) { this.context = context; this.prevIndex = prevIndex; this.newIndex = newIndex; @@ -209,26 +240,30 @@ public class ConfigWatch implements ApplicationEventPublisherAware, SmartLifecyc @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } RefreshEventData that = (RefreshEventData) o; - return Objects.equals(context, that.context) && - Objects.equals(prevIndex, that.prevIndex) && - Objects.equals(newIndex, that.newIndex); + return Objects.equals(this.context, that.context) + && Objects.equals(this.prevIndex, that.prevIndex) + && Objects.equals(this.newIndex, that.newIndex); } @Override public int hashCode() { - return Objects.hash(context, prevIndex, newIndex); + return Objects.hash(this.context, this.prevIndex, this.newIndex); } @Override public String toString() { - return new ToStringCreator(this) - .append("context", context) - .append("prevIndex", prevIndex) - .append("newIndex", newIndex) + return new ToStringCreator(this).append("context", this.context) + .append("prevIndex", this.prevIndex).append("newIndex", this.newIndex) .toString(); } + } + } diff --git a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigAutoConfiguration.java b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigAutoConfiguration.java index 9bdc113b..0e10ecdd 100644 --- a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigAutoConfiguration.java +++ b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,23 +36,30 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @ConditionalOnProperty(name = "spring.cloud.consul.config.enabled", matchIfMissing = true) public class ConsulConfigAutoConfiguration { + /** + * Name of the config watch task scheduler bean. + */ public static final String CONFIG_WATCH_TASK_SCHEDULER_NAME = "configWatchTaskScheduler"; @Configuration @ConditionalOnClass(RefreshEndpoint.class) protected static class ConsulRefreshConfiguration { + @Bean @ConditionalOnProperty(name = "spring.cloud.consul.config.watch.enabled", matchIfMissing = true) public ConfigWatch configWatch(ConsulConfigProperties properties, ConsulPropertySourceLocator locator, ConsulClient consul, - @Qualifier(CONFIG_WATCH_TASK_SCHEDULER_NAME) TaskScheduler taskScheduler) { - return new ConfigWatch(properties, consul, locator.getContextIndexes(), taskScheduler); + @Qualifier(CONFIG_WATCH_TASK_SCHEDULER_NAME) TaskScheduler taskScheduler) { + return new ConfigWatch(properties, consul, locator.getContextIndexes(), + taskScheduler); } @Bean(name = CONFIG_WATCH_TASK_SCHEDULER_NAME) @ConditionalOnProperty(name = "spring.cloud.consul.config.watch.enabled", matchIfMissing = true) - public TaskScheduler configWatchTaskScheduler() { + public TaskScheduler configWatchTaskScheduler() { return new ThreadPoolTaskScheduler(); } + } + } diff --git a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigBootstrapConfiguration.java b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigBootstrapConfiguration.java index d0a348b4..92706641 100644 --- a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigBootstrapConfiguration.java +++ b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigBootstrapConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,8 @@ package org.springframework.cloud.consul.config; import com.ecwid.consul.v1.ConsulClient; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.consul.ConditionalOnConsulEnabled; import org.springframework.cloud.consul.ConsulAutoConfiguration; @@ -41,6 +41,7 @@ public class ConsulConfigBootstrapConfiguration { @Import(ConsulAutoConfiguration.class) @ConditionalOnProperty(name = "spring.cloud.consul.config.enabled", matchIfMissing = true) protected static class ConsulPropertySourceConfiguration { + @Autowired private ConsulClient consul; @@ -53,7 +54,9 @@ public class ConsulConfigBootstrapConfiguration { @Bean public ConsulPropertySourceLocator consulPropertySourceLocator( ConsulConfigProperties consulConfigProperties) { - return new ConsulPropertySourceLocator(consul, consulConfigProperties); + return new ConsulPropertySourceLocator(this.consul, consulConfigProperties); } + } + } diff --git a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigProperties.java b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigProperties.java index d1f21ae7..b4d91c26 100644 --- a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigProperties.java +++ b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulConfigProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,21 +16,22 @@ package org.springframework.cloud.consul.config; +import javax.annotation.PostConstruct; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.style.ToStringCreator; import org.springframework.validation.annotation.Validated; -import javax.annotation.PostConstruct; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - /** * @author Spencer Gibb */ @ConfigurationProperties("spring.cloud.consul.config") @Validated public class ConsulConfigProperties { + private boolean enabled = true; private String prefix = "config"; @@ -45,8 +46,8 @@ public class ConsulConfigProperties { private Format format = Format.KEY_VALUE; /** - * If format is Format.PROPERTIES or Format.YAML - * then the following field is used as key to look up consul for configuration. + * If format is Format.PROPERTIES or Format.YAML then the following field is used as + * key to look up consul for configuration. */ @NotEmpty private String dataKey = "data"; @@ -80,103 +81,154 @@ public class ConsulConfigProperties { return this.enabled; } - public String getPrefix() { - return this.prefix; - } - - public @NotEmpty String getDefaultContext() { - return this.defaultContext; - } - - public @NotEmpty String getProfileSeparator() { - return this.profileSeparator; - } - - public @NotNull Format getFormat() { - return this.format; - } - - public @NotEmpty String getDataKey() { - return this.dataKey; - } - - public String getAclToken() { - return this.aclToken; - } - - public Watch getWatch() { - return this.watch; - } - - public boolean isFailFast() { - return this.failFast; - } - - public String getName() { - return this.name; - } - public void setEnabled(boolean enabled) { this.enabled = enabled; } + public String getPrefix() { + return this.prefix; + } + public void setPrefix(String prefix) { this.prefix = prefix; } + public @NotEmpty String getDefaultContext() { + return this.defaultContext; + } + public void setDefaultContext(@NotEmpty String defaultContext) { this.defaultContext = defaultContext; } + public @NotEmpty String getProfileSeparator() { + return this.profileSeparator; + } + public void setProfileSeparator(@NotEmpty String profileSeparator) { this.profileSeparator = profileSeparator; } + public @NotNull Format getFormat() { + return this.format; + } + public void setFormat(@NotNull Format format) { this.format = format; } + public @NotEmpty String getDataKey() { + return this.dataKey; + } + public void setDataKey(@NotEmpty String dataKey) { this.dataKey = dataKey; } + public String getAclToken() { + return this.aclToken; + } + public void setAclToken(String aclToken) { this.aclToken = aclToken; } + public Watch getWatch() { + return this.watch; + } + public void setWatch(Watch watch) { this.watch = watch; } + public boolean isFailFast() { + return this.failFast; + } + public void setFailFast(boolean failFast) { this.failFast = failFast; } + public String getName() { + return this.name; + } + public void setName(String name) { this.name = name; } @Override public String toString() { - return new ToStringCreator(this) - .append("enabled", enabled) - .append("prefix", prefix) - .append("defaultContext", defaultContext) - .append("profileSeparator", profileSeparator) - .append("format", format) - .append("dataKey", dataKey) - .append("aclToken", aclToken) - .append("watch", watch) - .append("failFast", failFast) - .append("name", name) - .toString(); + return new ToStringCreator(this).append("enabled", this.enabled) + .append("prefix", this.prefix) + .append("defaultContext", this.defaultContext) + .append("profileSeparator", this.profileSeparator) + .append("format", this.format).append("dataKey", this.dataKey) + .append("aclToken", this.aclToken).append("watch", this.watch) + .append("failFast", this.failFast).append("name", this.name).toString(); } + /** + * There are many ways in which we can specify configuration in consul i.e., + * + *
    + *
  1. Nested key value style: Where value is either a constant or part of the key + * (nested). For e.g., For following configuration a.b.c=something a.b.d=something + * else One can specify the configuration in consul with key as + * "../kv/config/application/a/b/c" and value as "something" and key as + * "../kv/config/application/a/b/d" and value as "something else"
  2. + *
  3. Entire contents of properties file as value For e.g., For following + * configuration a.b.c=something a.b.d=something else One can specify the + * configuration in consul with key as "../kv/config/application/properties" and value + * as whole configuration " a.b.c=something a.b.d=something else "
  4. + *
  5. as Json or YML. You get it.
  6. + *
+ * + * This enum specifies the different Formats/styles supported for loading the + * configuration. + * + * @author srikalyan.swayampakula + */ + public enum Format { + + /** + * Indicates that the configuration specified in consul is of type native key + * values. + */ + KEY_VALUE, + + /** + * Indicates that the configuration specified in consul is of property style i.e., + * value of the consul key would be a list of key=value pairs separated by new + * lines. + */ + PROPERTIES, + + /** + * Indicates that the configuration specified in consul is of YAML style i.e., + * value of the consul key would be YAML format. + */ + YAML, + + /** + * Indicates that the configuration specified in consul uses keys as files. This + * is useful for tools like git2consul. + */ + FILES, + + } + + /** + * Consul watch properties. + */ public static class Watch { - /** The number of seconds to wait (or block) for watch query, defaults to 55. - * Needs to be less than default ConsulClient (defaults to 60). To increase ConsulClient + + /** + * The number of seconds to wait (or block) for watch query, defaults to 55. Needs + * to be less than default ConsulClient (defaults to 60). To increase ConsulClient * timeout create a ConsulClient bean with a custom ConsulRawClient with a custom - * HttpClient. */ + * HttpClient. + */ private int waitTime = 55; /** If the watch is enabled. Defaults to true. */ @@ -192,83 +244,33 @@ public class ConsulConfigProperties { return this.waitTime; } - public boolean isEnabled() { - return this.enabled; - } - - public int getDelay() { - return this.delay; - } - public void setWaitTime(int waitTime) { this.waitTime = waitTime; } + public boolean isEnabled() { + return this.enabled; + } + public void setEnabled(boolean enabled) { this.enabled = enabled; } + public int getDelay() { + return this.delay; + } + public void setDelay(int delay) { this.delay = delay; } @Override public String toString() { - return new ToStringCreator(this) - .append("waitTime", waitTime) - .append("enabled", enabled) - .append("delay", delay) + return new ToStringCreator(this).append("waitTime", this.waitTime) + .append("enabled", this.enabled).append("delay", this.delay) .toString(); } - } - - /** - * There are many ways in which we can specify configuration in consul i.e., - * - *
    - *
  1. - * Nested key value style: Where value is either a constant or part of the key (nested). - * For e.g., For following configuration a.b.c=something a.b.d=something else One can - * specify the configuration in consul with key as "../kv/config/application/a/b/c" and - * value as "something" and key as "../kv/config/application/a/b/d" and value as - * "something else"
  2. - *
  3. - * Entire contents of properties file as value For e.g., For following configuration - * a.b.c=something a.b.d=something else One can specify the configuration in consul with - * key as "../kv/config/application/properties" and value as whole configuration " - * a.b.c=something a.b.d=something else "
  4. - *
  5. - * as Json or YML. You get it.
  6. - *
- * - * This enum specifies the different Formats/styles supported for loading the - * configuration. - * - * @author srikalyan.swayampakula - */ - public enum Format { - /** - * Indicates that the configuration specified in consul is of type native key values. - */ - KEY_VALUE, - - /** - * Indicates that the configuration specified in consul is of property style i.e., - * value of the consul key would be a list of key=value pairs separated by new lines. - */ - PROPERTIES, - - /** - * Indicates that the configuration specified in consul is of YAML style i.e., value - * of the consul key would be YAML format - */ - YAML, - - /** - * Indicates that the configuration specified in consul uses keys as files. - * This is useful for tools like git2consul. - */ - FILES, } + } diff --git a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulFilesPropertySource.java b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulFilesPropertySource.java index 57593091..f297ba25 100644 --- a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulFilesPropertySource.java +++ b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulFilesPropertySource.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,22 +26,28 @@ import static org.springframework.cloud.consul.config.ConsulConfigProperties.For * @author Spencer Gibb */ public class ConsulFilesPropertySource extends ConsulPropertySource { - public ConsulFilesPropertySource(String context, ConsulClient source, ConsulConfigProperties configProperties) { + + public ConsulFilesPropertySource(String context, ConsulClient source, + ConsulConfigProperties configProperties) { super(context, source, configProperties); } @Override public void init() { - //noop + // noop } public void init(GetValue value) { if (this.getContext().endsWith(".yml") || this.getContext().endsWith(".yaml")) { parseValue(value, YAML); - } else if (this.getContext().endsWith(".properties")) { + } + else if (this.getContext().endsWith(".properties")) { parseValue(value, PROPERTIES); - } else { - throw new IllegalStateException("Unknown files extension for context " + this.getContext()); + } + else { + throw new IllegalStateException( + "Unknown files extension for context " + this.getContext()); } } + } diff --git a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulPropertySource.java b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulPropertySource.java index 176c8181..91612ac3 100644 --- a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulPropertySource.java +++ b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulPropertySource.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,16 +24,16 @@ import java.util.Map; import java.util.Properties; import java.util.Set; -import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; -import org.springframework.core.env.EnumerablePropertySource; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.util.StringUtils; - import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.QueryParams; import com.ecwid.consul.v1.Response; import com.ecwid.consul.v1.kv.model.GetValue; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.util.StringUtils; + import static org.springframework.cloud.consul.config.ConsulConfigProperties.Format.PROPERTIES; import static org.springframework.cloud.consul.config.ConsulConfigProperties.Format.YAML; import static org.springframework.util.Base64Utils.decodeFromString; @@ -43,11 +43,12 @@ import static org.springframework.util.Base64Utils.decodeFromString; */ public class ConsulPropertySource extends EnumerablePropertySource { - private String context; - private ConsulConfigProperties configProperties; - private final Map properties = new LinkedHashMap<>(); + private String context; + + private ConsulConfigProperties configProperties; + private Long initialIndex; public ConsulPropertySource(String context, ConsulClient source, @@ -63,13 +64,13 @@ public class ConsulPropertySource extends EnumerablePropertySource this.context = this.context + "/"; } - Response> response = source.getKVValues(context, - configProperties.getAclToken(), QueryParams.DEFAULT); + Response> response = this.source.getKVValues(this.context, + this.configProperties.getAclToken(), QueryParams.DEFAULT); - initialIndex = response.getConsulIndex(); + this.initialIndex = response.getConsulIndex(); final List values = response.getValue(); - ConsulConfigProperties.Format format = configProperties.getFormat(); + ConsulConfigProperties.Format format = this.configProperties.getFormat(); switch (format) { case KEY_VALUE: parsePropertiesInKeyValueFormat(values); @@ -81,14 +82,13 @@ public class ConsulPropertySource extends EnumerablePropertySource } public Long getInitialIndex() { - return initialIndex; + return this.initialIndex; } /** * Parses the properties in key value style i.e., values are expected to be either a - * sub key or a constant - * - * @param values + * sub key or a constant. + * @param values values to parse */ protected void parsePropertiesInKeyValueFormat(List values) { if (values == null) { @@ -98,18 +98,18 @@ public class ConsulPropertySource extends EnumerablePropertySource for (GetValue getValue : values) { String key = getValue.getKey(); if (!StringUtils.endsWithIgnoreCase(key, "/")) { - key = key.replace(context, "").replace('/', '.'); + key = key.replace(this.context, "").replace('/', '.'); String value = getValue.getDecodedValue(); - properties.put(key, value); + this.properties.put(key, value); } } } /** * Parses the properties using the format which is not a key value style i.e., either - * java properties style or YAML style - * - * @param values + * java properties style or YAML style. + * @param values values to parse + * @param format format in which the values should be parsed */ protected void parsePropertiesWithNonKeyValueFormat(List values, ConsulConfigProperties.Format format) { @@ -118,8 +118,8 @@ public class ConsulPropertySource extends EnumerablePropertySource } for (GetValue getValue : values) { - String key = getValue.getKey().replace(context, ""); - if (configProperties.getDataKey().equals(key)) { + String key = getValue.getKey().replace(this.context, ""); + if (this.configProperties.getDataKey().equals(key)) { parseValue(getValue, format); } } @@ -134,8 +134,7 @@ public class ConsulPropertySource extends EnumerablePropertySource Properties props = generateProperties(value, format); for (Map.Entry entry : props.entrySet()) { - properties - .put(entry.getKey().toString(), entry.getValue()); + this.properties.put(entry.getKey().toString(), entry.getValue()); } } @@ -150,8 +149,8 @@ public class ConsulPropertySource extends EnumerablePropertySource props.load(new ByteArrayInputStream(value.getBytes("ISO-8859-1"))); } catch (IOException e) { - throw new IllegalArgumentException(value - + " can't be encoded using ISO-8859-1"); + throw new IllegalArgumentException( + value + " can't be encoded using ISO-8859-1"); } return props; @@ -168,34 +167,38 @@ public class ConsulPropertySource extends EnumerablePropertySource /** * @deprecated As of 1.1.0 use {@link GetValue#getDecodedValue()}. + * @param value encoded value + * @return the decoded string */ @Deprecated public String getDecoded(String value) { - if (value == null) + if (value == null) { return null; + } return new String(decodeFromString(value)); } protected Map getProperties() { - return properties; + return this.properties; } protected ConsulConfigProperties getConfigProperties() { - return configProperties; + return this.configProperties; } protected String getContext() { - return context; + return this.context; } @Override public Object getProperty(String name) { - return properties.get(name); + return this.properties.get(name); } @Override public String[] getPropertyNames() { - Set strings = properties.keySet(); + Set strings = this.properties.keySet(); return strings.toArray(new String[strings.size()]); } + } diff --git a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocator.java b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocator.java index d9848de5..142f28f3 100644 --- a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocator.java +++ b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,6 +48,7 @@ import static org.springframework.cloud.consul.config.ConsulConfigProperties.For public class ConsulPropertySourceLocator implements PropertySourceLocator { private static final Log log = LogFactory.getLog(ConsulPropertySourceLocator.class); + private final ConsulClient consul; private final ConsulConfigProperties properties; @@ -56,18 +57,19 @@ public class ConsulPropertySourceLocator implements PropertySourceLocator { private final LinkedHashMap contextIndex = new LinkedHashMap<>(); - public ConsulPropertySourceLocator(ConsulClient consul, ConsulConfigProperties properties) { + public ConsulPropertySourceLocator(ConsulClient consul, + ConsulConfigProperties properties) { this.consul = consul; this.properties = properties; } @Deprecated public List getContexts() { - return contexts; + return this.contexts; } public LinkedHashMap getContextIndexes() { - return contextIndex; + return this.contextIndex; } @Override @@ -76,7 +78,7 @@ public class ConsulPropertySourceLocator implements PropertySourceLocator { if (environment instanceof ConfigurableEnvironment) { ConfigurableEnvironment env = (ConfigurableEnvironment) environment; - String appName = properties.getName(); + String appName = this.properties.getName(); if (appName == null) { appName = env.getProperty("spring.application.name"); @@ -89,13 +91,15 @@ public class ConsulPropertySourceLocator implements PropertySourceLocator { List suffixes = new ArrayList<>(); if (this.properties.getFormat() != FILES) { suffixes.add("/"); - } else { + } + else { suffixes.add(".yml"); suffixes.add(".yaml"); suffixes.add(".properties"); } - String defaultContext = getContext(prefix, this.properties.getDefaultContext()); + String defaultContext = getContext(prefix, + this.properties.getDefaultContext()); for (String suffix : suffixes) { this.contexts.add(defaultContext + suffix); @@ -121,25 +125,32 @@ public class ConsulPropertySourceLocator implements PropertySourceLocator { try { ConsulPropertySource propertySource = null; if (this.properties.getFormat() == FILES) { - Response response = this.consul.getKVValue(propertySourceContext, this.properties.getAclToken()); + Response response = this.consul.getKVValue( + propertySourceContext, this.properties.getAclToken()); addIndex(propertySourceContext, response.getConsulIndex()); if (response.getValue() != null) { - ConsulFilesPropertySource filesPropertySource = new ConsulFilesPropertySource(propertySourceContext, this.consul, this.properties); + ConsulFilesPropertySource filesPropertySource = new ConsulFilesPropertySource( + propertySourceContext, this.consul, this.properties); filesPropertySource.init(response.getValue()); propertySource = filesPropertySource; } - } else { - propertySource = create(propertySourceContext, contextIndex); + } + else { + propertySource = create(propertySourceContext, this.contextIndex); } if (propertySource != null) { composite.addPropertySource(propertySource); } - } catch (Exception e) { + } + catch (Exception e) { if (this.properties.isFailFast()) { - log.error("Fail fast is set and there was an error reading configuration from consul."); + log.error( + "Fail fast is set and there was an error reading configuration from consul."); ReflectionUtils.rethrowRuntimeException(e); - } else { - log.warn("Unable to load consul config from "+ propertySourceContext, e); + } + else { + log.warn("Unable to load consul config from " + + propertySourceContext, e); } } } @@ -152,26 +163,30 @@ public class ConsulPropertySourceLocator implements PropertySourceLocator { private String getContext(String prefix, String context) { if (StringUtils.isEmpty(prefix)) { return context; - } else { + } + else { return prefix + "/" + context; } } private void addIndex(String propertySourceContext, Long consulIndex) { - contextIndex.put(propertySourceContext, consulIndex); + this.contextIndex.put(propertySourceContext, consulIndex); } private ConsulPropertySource create(String context, Map contextIndex) { - ConsulPropertySource propertySource = new ConsulPropertySource(context, this.consul, this.properties); + ConsulPropertySource propertySource = new ConsulPropertySource(context, + this.consul, this.properties); propertySource.init(); addIndex(context, propertySource.getInitialIndex()); return propertySource; } private void addProfiles(List contexts, String baseContext, - List profiles, String suffix) { + List profiles, String suffix) { for (String profile : profiles) { - contexts.add(baseContext + this.properties.getProfileSeparator() + profile + suffix); + contexts.add(baseContext + this.properties.getProfileSeparator() + profile + + suffix); } } + } diff --git a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/PropertySourcesLocatedEvent.java b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/PropertySourcesLocatedEvent.java index 6eed107d..e02c3247 100644 --- a/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/PropertySourcesLocatedEvent.java +++ b/spring-cloud-consul-config/src/main/java/org/springframework/cloud/consul/config/PropertySourcesLocatedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,10 @@ package org.springframework.cloud.consul.config; -import org.springframework.context.ApplicationEvent; - import java.util.LinkedHashMap; +import org.springframework.context.ApplicationEvent; + /** * @author Spencer Gibb */ @@ -29,15 +29,17 @@ public class PropertySourcesLocatedEvent extends ApplicationEvent { /** * Create a new ApplicationEvent. - * * @param source the object on which the event initially occurred (never {@code null}) + * @param contextsToIndexes contexts to indexes */ - public PropertySourcesLocatedEvent(Object source, LinkedHashMap contextsToIndexes) { + public PropertySourcesLocatedEvent(Object source, + LinkedHashMap contextsToIndexes) { super(source); this.contextsToIndexes = contextsToIndexes; } public LinkedHashMap getContextsToIndexes() { - return contextsToIndexes; + return this.contextsToIndexes; } + } diff --git a/spring-cloud-consul-config/src/main/resources/META-INF/spring.factories b/spring-cloud-consul-config/src/main/resources/META-INF/spring.factories index d1699b34..1e7e41f9 100644 --- a/spring-cloud-consul-config/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-consul-config/src/main/resources/META-INF/spring.factories @@ -1,7 +1,6 @@ # Auto Configuration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.consul.config.ConsulConfigAutoConfiguration - # Bootstrap Configuration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.consul.config.ConsulConfigBootstrapConfiguration diff --git a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConfigWatchTests.java b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConfigWatchTests.java index 37ed4511..24c32cd0 100644 --- a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConfigWatchTests.java +++ b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConfigWatchTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,21 +16,22 @@ package org.springframework.cloud.consul.config; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; + import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.QueryParams; import com.ecwid.consul.v1.Response; import com.ecwid.consul.v1.kv.model.GetValue; import org.junit.Before; import org.junit.Test; + import org.springframework.cloud.endpoint.event.RefreshEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.util.StringUtils; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; - import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; @@ -52,14 +53,15 @@ public class ConfigWatchTests { @Before public void setUp() throws Exception { - configProperties = new ConsulConfigProperties(); + this.configProperties = new ConsulConfigProperties(); } @Test public void watchPublishesEventWithAcl() { ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher.class); - setupWatch(eventPublisher, new GetValue(), "/app/", "2ee647bd-bd69-4118-9f34-b9a6e9e60746"); + setupWatch(eventPublisher, new GetValue(), "/app/", + "2ee647bd-bd69-4118-9f34-b9a6e9e60746"); verify(eventPublisher, atLeastOnce()).publishEvent(any(RefreshEvent.class)); } @@ -86,17 +88,19 @@ public class ConfigWatchTests { public void watchForFileFormatPublishesEvent() { ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher.class); - configProperties.setFormat(FILES); - setupWatch(eventPublisher, new GetValue(), "/config/app.yml" ); + this.configProperties.setFormat(FILES); + setupWatch(eventPublisher, new GetValue(), "/config/app.yml"); verify(eventPublisher, times(1)).publishEvent(any(RefreshEvent.class)); } - private void setupWatch(ApplicationEventPublisher eventPublisher, GetValue getValue, String context) { + private void setupWatch(ApplicationEventPublisher eventPublisher, GetValue getValue, + String context) { setupWatch(eventPublisher, getValue, context, null); } - private void setupWatch(ApplicationEventPublisher eventPublisher, GetValue getValue, String context, String aclToken) { + private void setupWatch(ApplicationEventPublisher eventPublisher, GetValue getValue, + String context, String aclToken) { ConsulClient consul = mock(ConsulClient.class); List getValues = null; @@ -105,15 +109,17 @@ public class ConfigWatchTests { } Response> response = new Response<>(getValues, 1L, false, 1L); - when(consul.getKVValues(eq(context), nullable(String.class), any(QueryParams.class))).thenReturn(response); + when(consul.getKVValues(eq(context), nullable(String.class), + any(QueryParams.class))).thenReturn(response); if (StringUtils.hasText(aclToken)) { - configProperties.setAclToken(aclToken); + this.configProperties.setAclToken(aclToken); } LinkedHashMap initialIndexes = new LinkedHashMap<>(); initialIndexes.put(context, 0L); - ConfigWatch watch = new ConfigWatch(configProperties, consul, initialIndexes); + ConfigWatch watch = new ConfigWatch(this.configProperties, consul, + initialIndexes); watch.setApplicationEventPublisher(eventPublisher); watch.start(); @@ -123,7 +129,7 @@ public class ConfigWatchTests { @Test public void firstCallDoesNotPublishEvent() { ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher.class); - configProperties.setFormat(FILES); + this.configProperties.setFormat(FILES); GetValue getValue = new GetValue(); String context = "/config/app.yml"; @@ -131,9 +137,11 @@ public class ConfigWatchTests { List getValues = Collections.singletonList(getValue); Response> response = new Response<>(getValues, 1L, false, 1L); - when(consul.getKVValues(eq(context), anyString(), any(QueryParams.class))).thenReturn(response); + when(consul.getKVValues(eq(context), anyString(), any(QueryParams.class))) + .thenReturn(response); - ConfigWatch watch = new ConfigWatch(configProperties, consul, new LinkedHashMap()); + ConfigWatch watch = new ConfigWatch(this.configProperties, consul, + new LinkedHashMap()); watch.setApplicationEventPublisher(eventPublisher); watch.watchConfigKeyValues(); diff --git a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulConfigBootstrapConfigurationTests.java b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulConfigBootstrapConfigurationTests.java index 783ebdaf..2fdc9029 100644 --- a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulConfigBootstrapConfigurationTests.java +++ b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulConfigBootstrapConfigurationTests.java @@ -1,50 +1,76 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.consul.config; -import org.junit.Assert; import org.junit.Test; + import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Edvin Eriksson */ public class ConsulConfigBootstrapConfigurationTests { + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); /** - * Tests that the auto-config bean backs off if a user provided their own + * Tests that the auto-config bean backs off if a user provided their own. */ @Test public void testConfigPropsBeanBacksOff() { - contextRunner - .withUserConfiguration(TestConfig.class) - .withUserConfiguration(ConsulConfigBootstrapConfiguration.class) - .run(context -> { - ConsulConfigProperties config = context.getBean(ConsulConfigProperties.class); - Assert.assertEquals("Prefix did not match", "platform-config", config.getPrefix()); - Assert.assertEquals("Default context did not match", "defaults", config.getDefaultContext()); - }); + this.contextRunner.withUserConfiguration(TestConfig.class) + .withUserConfiguration(ConsulConfigBootstrapConfiguration.class) + .run(context -> { + ConsulConfigProperties config = context + .getBean(ConsulConfigProperties.class); + assertThat(config.getPrefix()).as("Prefix did not match") + .isEqualTo("platform-config"); + assertThat(config.getDefaultContext()) + .as("Default context did not match").isEqualTo("defaults"); + }); } /** - * Tests that the auto-config bean kicks in if the user did not provide any custom bean. + * Tests that the auto-config bean kicks in if the user did not provide any custom + * bean. */ @Test public void testConfigPropsBeanKicksIn() { - contextRunner - .withUserConfiguration(ConsulConfigBootstrapConfiguration.class) - .run(context -> { - ConsulConfigProperties config = context.getBean(ConsulConfigProperties.class); - Assert.assertEquals("Prefix did not match", "config", config.getPrefix()); - Assert.assertEquals("Default context did not match", "application", config.getDefaultContext()); - }); + this.contextRunner.withUserConfiguration(ConsulConfigBootstrapConfiguration.class) + .run(context -> { + ConsulConfigProperties config = context + .getBean(ConsulConfigProperties.class); + assertThat(config.getPrefix()).as("Prefix did not match") + .isEqualTo("config"); + assertThat(config.getDefaultContext()) + .as("Default context did not match").isEqualTo("application"); + }); } + } /** - * Test config that simulates a "user provided bean" + * Test config that simulates a "user provided bean". */ class TestConfig { + @Bean public ConsulConfigProperties consulConfigProperties() { ConsulConfigProperties config = new ConsulConfigProperties(); @@ -52,4 +78,5 @@ class TestConfig { config.setDefaultContext("defaults"); return config; } -} \ No newline at end of file + +} diff --git a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertyPrefixTests.java b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertyPrefixTests.java index 460bed9e..e7cfb0ee 100644 --- a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertyPrefixTests.java +++ b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertyPrefixTests.java @@ -1,15 +1,29 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.consul.config; import com.ecwid.consul.v1.ConsulClient; import org.junit.After; import org.junit.Before; import org.junit.Test; + import org.springframework.cloud.consul.ConsulProperties; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class ConsulPropertyPrefixTests { @@ -18,37 +32,44 @@ public class ConsulPropertyPrefixTests { @Before public void setup() { ConsulProperties properties = new ConsulProperties(); - client = new ConsulClient(properties.getHost(), properties.getPort()); + this.client = new ConsulClient(properties.getHost(), properties.getPort()); } @After public void teardown() { - client.deleteKVValues(""); + this.client.deleteKVValues(""); } @Test public void testEmptyPrefix() { // because prefix is empty, a leading forward slash is omitted String kvContext = "appname"; - client.setKVValue(kvContext + "/fooprop", "fookvval"); - client.setKVValue(kvContext + "/bar/prop", "8080"); + this.client.setKVValue(kvContext + "/fooprop", "fookvval"); + this.client.setKVValue(kvContext + "/bar/prop", "8080"); - ConsulPropertySource source = getConsulPropertySource(new ConsulConfigProperties(), kvContext); + ConsulPropertySource source = getConsulPropertySource( + new ConsulConfigProperties(), kvContext); assertProperties(source, "fookvval", "8080"); } - private void assertProperties(ConsulPropertySource source, Object fooval, Object barval) { - assertThat("fooprop was wrong", source.getProperty("fooprop"), is(equalTo(fooval))); - assertThat("bar.prop was wrong", source.getProperty("bar.prop"), is(equalTo(barval))); + private void assertProperties(ConsulPropertySource source, Object fooval, + Object barval) { + assertThat(source.getProperty("fooprop")).as("fooprop was wrong") + .isEqualTo(fooval); + assertThat(source.getProperty("bar.prop")).as("bar.prop was wrong") + .isEqualTo(barval); } @SuppressWarnings("Duplicates") - private ConsulPropertySource getConsulPropertySource(ConsulConfigProperties configProperties, String context) { - ConsulPropertySource source = new ConsulPropertySource(context, client, configProperties); + private ConsulPropertySource getConsulPropertySource( + ConsulConfigProperties configProperties, String context) { + ConsulPropertySource source = new ConsulPropertySource(context, this.client, + configProperties); source.init(); String[] names = source.getPropertyNames(); - assertThat("names was null", names, is(notNullValue())); - assertThat("names was wrong size", names.length, is(equalTo(2))); + assertThat(names).as("names was null").isNotNull(); + assertThat(names.length).as("names was wrong size").isEqualTo(2); return source; } + } diff --git a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorAppNameCustomizedTests.java b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorAppNameCustomizedTests.java index 9f1d7e28..870d7df5 100644 --- a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorAppNameCustomizedTests.java +++ b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorAppNameCustomizedTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,11 @@ package org.springframework.cloud.consul.config; import java.util.UUID; +import com.ecwid.consul.v1.ConsulClient; import org.junit.After; import org.junit.Before; import org.junit.Test; + import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; @@ -30,57 +32,58 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.test.annotation.DirtiesContext; -import com.ecwid.consul.v1.ConsulClient; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Spencer Gibb */ @DirtiesContext public class ConsulPropertySourceLocatorAppNameCustomizedTests { + private static final String PREFIX = "_propertySourceLocatorAppNameCustomizedTests_config__"; + private static final String ROOT = PREFIX + UUID.randomUUID(); + private static final String VALUE1 = "testPropVal"; + private static final String TEST_PROP = "testProp"; + private static final String CONFIG_NAME = "myconfigfolder"; - private static final String KEY1 = ROOT + "/"+ CONFIG_NAME +"/"+ TEST_PROP; + + private static final String KEY1 = ROOT + "/" + CONFIG_NAME + "/" + TEST_PROP; + private static final String VALUE2 = "testPropVal2"; + private static final String TEST_PROP2 = "testProp2"; - private static final String KEY2 = ROOT + "/"+ CONFIG_NAME +"/"+ TEST_PROP2; + + private static final String KEY2 = ROOT + "/" + CONFIG_NAME + "/" + TEST_PROP2; private ConfigurableApplicationContext context; - @Configuration - @EnableAutoConfiguration - static class Config { - - } - private ConfigurableEnvironment environment; + private ConsulClient client; + private ConsulProperties properties; @Before public void setup() { this.properties = new ConsulProperties(); - this.client = new ConsulClient(properties.getHost(), properties.getPort()); + this.client = new ConsulClient(this.properties.getHost(), + this.properties.getPort()); this.client.deleteKVValues(PREFIX); this.client.setKVValue(KEY1, VALUE1); this.client.setKVValue(KEY2, VALUE2); - this.context = new SpringApplicationBuilder(Config.class) .web(WebApplicationType.NONE) .run("--spring.application.name=testConsulPropertySourceLocatorAppNameCustomized", - "--spring.cloud.consul.config.name="+CONFIG_NAME, - "--spring.cloud.consul.config.prefix="+ROOT); + "--spring.cloud.consul.config.name=" + CONFIG_NAME, + "--spring.cloud.consul.config.prefix=" + ROOT); - this.client = context.getBean(ConsulClient.class); - this.properties = context.getBean(ConsulProperties.class); - this.environment = context.getEnvironment(); + this.client = this.context.getBean(ConsulClient.class); + this.properties = this.context.getBean(ConsulProperties.class); + this.environment = this.context.getEnvironment(); } @After @@ -92,9 +95,16 @@ public class ConsulPropertySourceLocatorAppNameCustomizedTests { @Test public void propertyLoaded() throws Exception { String testProp = this.environment.getProperty(TEST_PROP); - assertThat("testProp was wrong", testProp, is(equalTo(VALUE1))); + assertThat(testProp).as("testProp was wrong").isEqualTo(VALUE1); String testProp2 = this.environment.getProperty(TEST_PROP2); - assertThat("testProp2 was wrong", testProp2, is(equalTo(VALUE2))); + assertThat(testProp2).as("testProp2 was wrong").isEqualTo(VALUE2); } + + @Configuration + @EnableAutoConfiguration + static class Config { + + } + } diff --git a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorFailFastTests.java b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorFailFastTests.java index 8080ba64..630450e0 100644 --- a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorFailFastTests.java +++ b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorFailFastTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.cloud.consul.config; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Configuration; @@ -29,22 +30,21 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @author Spencer Gibb */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulPropertySourceLocatorFailFastTests.Config.class, - properties = {"spring.application.name=testConsulPropertySourceLocatorFailFast", +@SpringBootTest(classes = ConsulPropertySourceLocatorFailFastTests.Config.class, properties = { + "spring.application.name=testConsulPropertySourceLocatorFailFast", "spring.cloud.consul.host=53210a7c-4809-42cb-8b30-057d2db85fcc", - "spring.cloud.consul.port=65530", - "spring.cloud.consul.retry.maxAttempts=0", - "spring.cloud.consul.config.failFast=false"}, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.port=65530", "spring.cloud.consul.retry.maxAttempts=0", + "spring.cloud.consul.config.failFast=false" }, webEnvironment = RANDOM_PORT) public class ConsulPropertySourceLocatorFailFastTests { - @Configuration - @EnableAutoConfiguration - static class Config { - } - @Test public void testFailFastFalse() { } + @Configuration + @EnableAutoConfiguration + static class Config { + + } + } diff --git a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorFilesTests.java b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorFilesTests.java index 536d0315..e433d183 100644 --- a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorFilesTests.java +++ b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorFilesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,9 +20,11 @@ import java.util.Collection; import java.util.Iterator; import java.util.UUID; +import com.ecwid.consul.v1.ConsulClient; import org.junit.After; import org.junit.Before; import org.junit.Test; + import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; @@ -35,62 +37,59 @@ import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import org.springframework.test.annotation.DirtiesContext; -import com.ecwid.consul.v1.ConsulClient; - -import static org.hamcrest.Matchers.endsWith; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.typeCompatibleWith; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Spencer Gibb */ @DirtiesContext public class ConsulPropertySourceLocatorFilesTests { + public static final String PREFIX = "_propertySourceLocatorFilesTests_config__"; + public static final String ROOT = PREFIX + UUID.randomUUID(); + public static final String APP_NAME = "testFilesFormat"; + public static final String APPLICATION_YML = "/application.yml"; + public static final String APPLICATION_DEV_YML = "/application-dev.yaml"; - public static final String APP_NAME_PROPS = "/"+APP_NAME+".properties"; - public static final String APP_NAME_DEV_PROPS = "/"+APP_NAME+"-dev.properties"; + + public static final String APP_NAME_PROPS = "/" + APP_NAME + ".properties"; + + public static final String APP_NAME_DEV_PROPS = "/" + APP_NAME + "-dev.properties"; private ConfigurableApplicationContext context; - @Configuration - @EnableAutoConfiguration - static class Config { - - } - private ConfigurableEnvironment environment; + private ConsulClient client; + private ConsulProperties properties; @Before public void setup() { this.properties = new ConsulProperties(); - this.client = new ConsulClient(properties.getHost(), properties.getPort()); - this.client.setKVValue(ROOT+ APPLICATION_YML, "foo: bar\nmy.baz: ${foo}"); - this.client.setKVValue(ROOT+ APPLICATION_DEV_YML, "foo: bar-dev\nmy.baz: ${foo}"); - this.client.setKVValue(ROOT+"/master.ref", UUID.randomUUID().toString()); - this.client.setKVValue(ROOT+APP_NAME_PROPS, "foo: bar-app\nmy.baz: ${foo}"); - this.client.setKVValue(ROOT+APP_NAME_DEV_PROPS, "foo: bar-app-dev\nmy.baz: ${foo}"); + this.client = new ConsulClient(this.properties.getHost(), + this.properties.getPort()); + this.client.setKVValue(ROOT + APPLICATION_YML, "foo: bar\nmy.baz: ${foo}"); + this.client.setKVValue(ROOT + APPLICATION_DEV_YML, + "foo: bar-dev\nmy.baz: ${foo}"); + this.client.setKVValue(ROOT + "/master.ref", UUID.randomUUID().toString()); + this.client.setKVValue(ROOT + APP_NAME_PROPS, "foo: bar-app\nmy.baz: ${foo}"); + this.client.setKVValue(ROOT + APP_NAME_DEV_PROPS, + "foo: bar-app-dev\nmy.baz: ${foo}"); this.context = new SpringApplicationBuilder(Config.class) - .web(WebApplicationType.NONE) - .run("--spring.application.name="+ APP_NAME, - "--spring.cloud.consul.config.prefix="+ROOT, + .web(WebApplicationType.NONE).run("--spring.application.name=" + APP_NAME, + "--spring.cloud.consul.config.prefix=" + ROOT, "--spring.cloud.consul.config.format=FILES", "--spring.profiles.active=dev", "spring.cloud.consul.config.watch.delay=1"); - this.client = context.getBean(ConsulClient.class); - this.properties = context.getBean(ConsulProperties.class); - this.environment = context.getEnvironment(); + this.client = this.context.getBean(ConsulClient.class); + this.properties = this.context.getBean(ConsulProperties.class); + this.environment = this.context.getEnvironment(); } @After @@ -104,32 +103,48 @@ public class ConsulPropertySourceLocatorFilesTests { @Test public void propertySourcesFound() throws Exception { String foo = this.environment.getProperty("foo"); - assertThat("foo was wrong", foo, is(equalTo("bar-app-dev"))); + assertThat(foo).as("foo was wrong").isEqualTo("bar-app-dev"); String myBaz = this.environment.getProperty("my.baz"); - assertThat("my.baz was wrong", myBaz, is(equalTo("bar-app-dev"))); + assertThat(myBaz).as("my.baz was wrong").isEqualTo("bar-app-dev"); MutablePropertySources propertySources = this.environment.getPropertySources(); - PropertySource bootstrapProperties = propertySources.get("bootstrapProperties"); - assertThat("bootstrapProperties was null", bootstrapProperties, is(notNullValue())); - assertThat("bootstrapProperties was wrong type", bootstrapProperties.getClass(), is(typeCompatibleWith(CompositePropertySource.class))); + PropertySource bootstrapProperties = propertySources + .get("bootstrapProperties"); + assertThat(bootstrapProperties).as("bootstrapProperties was null").isNotNull(); + assertThat(bootstrapProperties.getClass()) + .as("bootstrapProperties was wrong type") + .isInstanceOf(CompositePropertySource.class); - Collection> consulSources = ((CompositePropertySource) bootstrapProperties).getPropertySources(); - assertThat("consulSources was wrong size", consulSources, hasSize(1)); + Collection> consulSources = ((CompositePropertySource) bootstrapProperties) + .getPropertySources(); + assertThat(consulSources).as("consulSources was wrong size").hasSize(1); PropertySource consulSource = consulSources.iterator().next(); - assertThat("consulSource was wrong type", consulSource.getClass(), is(typeCompatibleWith(CompositePropertySource.class))); - Collection> fileSources = ((CompositePropertySource) consulSource).getPropertySources(); - assertThat("fileSources was wrong size", fileSources, hasSize(4)); + assertThat(consulSource.getClass()).as("consulSource was wrong type") + .isInstanceOf(CompositePropertySource.class); + Collection> fileSources = ((CompositePropertySource) consulSource) + .getPropertySources(); + assertThat(fileSources).as("fileSources was wrong size").hasSize(4); - assertFileSourceNames(fileSources, APP_NAME_DEV_PROPS, APP_NAME_PROPS, APPLICATION_DEV_YML, APPLICATION_YML); + assertFileSourceNames(fileSources, APP_NAME_DEV_PROPS, APP_NAME_PROPS, + APPLICATION_DEV_YML, APPLICATION_YML); } - private void assertFileSourceNames(Collection> fileSources, String... names) { + private void assertFileSourceNames(Collection> fileSources, + String... names) { Iterator> iterator = fileSources.iterator(); for (String name : names) { PropertySource fileSource = iterator.next(); - assertThat("fileSources was wrong name", fileSource.getName(), endsWith(name)); + assertThat(fileSource.getName()).as("fileSources was wrong name") + .endsWith(name); } } + + @Configuration + @EnableAutoConfiguration + static class Config { + + } + } diff --git a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorTests.java b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorTests.java index 39706f82..27fcb906 100644 --- a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorTests.java +++ b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceLocatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,12 @@ import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import com.ecwid.consul.v1.ConsulClient; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; + import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; @@ -36,35 +38,117 @@ import org.springframework.context.event.EventListener; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.test.annotation.DirtiesContext; -import com.ecwid.consul.v1.ConsulClient; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Spencer Gibb */ @DirtiesContext public class ConsulPropertySourceLocatorTests { + private static final String APP_NAME = "testConsulPropertySourceLocator"; + private static final String PREFIX = "_propertySourceLocatorTests_config__"; + private static final String ROOT = PREFIX + UUID.randomUUID(); + private static final String VALUE1 = "testPropVal"; + private static final String TEST_PROP = "testProp"; + private static final String TEST_PROP_CANONICAL = "test-prop"; - private static final String KEY1 = ROOT + "/application/"+ TEST_PROP; + + private static final String KEY1 = ROOT + "/application/" + TEST_PROP; + private static final String VALUE2 = "testPropVal2"; + private static final String TEST_PROP2 = "testProp2"; + private static final String TEST_PROP2_CANONICAL = "test-prop2"; - private static final String KEY2 = ROOT + "/application/"+ TEST_PROP2; + + private static final String KEY2 = ROOT + "/application/" + TEST_PROP2; + private static final String TEST_PROP3 = "testProp3"; + private static final String TEST_PROP3_CANONICAL = "test-prop3"; - private static final String KEY3 = ROOT + "/"+APP_NAME+"/"+ TEST_PROP3; + + private static final String KEY3 = ROOT + "/" + APP_NAME + "/" + TEST_PROP3; private ConfigurableApplicationContext context; + private ConfigurableEnvironment environment; + + private ConsulClient client; + + private ConsulProperties properties; + + @Before + public void setup() { + this.properties = new ConsulProperties(); + this.client = new ConsulClient(this.properties.getHost(), + this.properties.getPort()); + this.client.deleteKVValues(PREFIX); + this.client.setKVValue(KEY1, VALUE1); + this.client.setKVValue(KEY2, VALUE2); + + this.context = new SpringApplicationBuilder(Config.class) + .web(WebApplicationType.NONE).run("--SPRING_APPLICATION_NAME=" + APP_NAME, + "--spring.cloud.consul.config.prefix=" + ROOT, + "spring.cloud.consul.config.watch.delay=10"); + + this.client = this.context.getBean(ConsulClient.class); + this.properties = this.context.getBean(ConsulProperties.class); + this.environment = this.context.getEnvironment(); + } + + @After + public void teardown() { + this.client.deleteKVValues(PREFIX); + this.context.close(); + } + + @Test + public void propertyLoaded() throws Exception { + String testProp = this.environment.getProperty(TEST_PROP2_CANONICAL); + assertThat(testProp).as("testProp was wrong").isEqualTo(VALUE2); + } + + @Test + @Ignore // FIXME broken tests with boot 2.0.0 + public void propertyLoadedAndUpdated() throws Exception { + String testProp = this.environment.getProperty(TEST_PROP_CANONICAL); + assertThat(testProp).as("testProp was wrong").isEqualTo(VALUE1); + + this.client.setKVValue(KEY1, "testPropValUpdate"); + + CountDownLatch latch = this.context.getBean("countDownLatch1", + CountDownLatch.class); + boolean receivedEvent = latch.await(15, TimeUnit.SECONDS); + assertThat(receivedEvent).as("listener didn't receive event").isTrue(); + + testProp = this.environment.getProperty(TEST_PROP_CANONICAL); + assertThat(testProp).as("testProp was wrong after update") + .isEqualTo("testPropValUpdate"); + } + + @Test + @Ignore // FIXME broken tests with boot 2.0.0 + public void contextDoesNotExistThenExists() throws Exception { + String testProp = this.environment.getProperty(TEST_PROP3_CANONICAL); + assertThat(testProp).as("testProp was wrong").isNull(); + + this.client.setKVValue(KEY3, "testPropValInsert"); + + CountDownLatch latch = this.context.getBean("countDownLatch2", + CountDownLatch.class); + boolean receivedEvent = latch.await(15, TimeUnit.SECONDS); + assertThat(receivedEvent).as("listener didn't receive event").isTrue(); + + testProp = this.environment.getProperty(TEST_PROP3_CANONICAL); + assertThat(testProp).as(TEST_PROP3 + " was wrong after update") + .isEqualTo("testPropValInsert"); + } + @Configuration @EnableAutoConfiguration static class Config { @@ -83,77 +167,12 @@ public class ConsulPropertySourceLocatorTests { public void handle(EnvironmentChangeEvent event) { if (event.getKeys().contains(TEST_PROP)) { countDownLatch1().countDown(); - } else if (event.getKeys().contains(TEST_PROP3)) { + } + else if (event.getKeys().contains(TEST_PROP3)) { countDownLatch2().countDown(); } } + } - private ConfigurableEnvironment environment; - private ConsulClient client; - private ConsulProperties properties; - - @Before - public void setup() { - this.properties = new ConsulProperties(); - this.client = new ConsulClient(properties.getHost(), properties.getPort()); - this.client.deleteKVValues(PREFIX); - this.client.setKVValue(KEY1, VALUE1); - this.client.setKVValue(KEY2, VALUE2); - - - this.context = new SpringApplicationBuilder(Config.class) - .web(WebApplicationType.NONE) - .run("--SPRING_APPLICATION_NAME="+ APP_NAME, - "--spring.cloud.consul.config.prefix="+ROOT, - "spring.cloud.consul.config.watch.delay=10"); - - this.client = context.getBean(ConsulClient.class); - this.properties = context.getBean(ConsulProperties.class); - this.environment = context.getEnvironment(); - } - - @After - public void teardown() { - this.client.deleteKVValues(PREFIX); - this.context.close(); - } - - @Test - public void propertyLoaded() throws Exception { - String testProp = this.environment.getProperty(TEST_PROP2_CANONICAL); - assertThat("testProp was wrong", testProp, is(equalTo(VALUE2))); - } - - @Test - @Ignore // FIXME broken tests with boot 2.0.0 - public void propertyLoadedAndUpdated() throws Exception { - String testProp = this.environment.getProperty(TEST_PROP_CANONICAL); - assertThat("testProp was wrong", testProp, is(equalTo(VALUE1))); - - this.client.setKVValue(KEY1, "testPropValUpdate"); - - CountDownLatch latch = this.context.getBean("countDownLatch1", CountDownLatch.class); - boolean receivedEvent = latch.await(15, TimeUnit.SECONDS); - assertThat("listener didn't receive event", receivedEvent, is(true)); - - testProp = this.environment.getProperty(TEST_PROP_CANONICAL); - assertThat("testProp was wrong after update", testProp, is(equalTo("testPropValUpdate"))); - } - - @Test - @Ignore // FIXME broken tests with boot 2.0.0 - public void contextDoesNotExistThenExists() throws Exception { - String testProp = this.environment.getProperty(TEST_PROP3_CANONICAL); - assertThat("testProp was wrong", testProp, is(nullValue())); - - this.client.setKVValue(KEY3, "testPropValInsert"); - - CountDownLatch latch = this.context.getBean("countDownLatch2", CountDownLatch.class); - boolean receivedEvent = latch.await(15, TimeUnit.SECONDS); - assertThat("listener didn't receive event", receivedEvent, is(true)); - - testProp = this.environment.getProperty(TEST_PROP3_CANONICAL); - assertThat(TEST_PROP3 + " was wrong after update", testProp, is(equalTo("testPropValInsert"))); - } } diff --git a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceTests.java b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceTests.java index af23bfc7..cda33307 100644 --- a/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceTests.java +++ b/spring-cloud-consul-config/src/test/java/org/springframework/cloud/consul/config/ConsulPropertySourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,67 +16,78 @@ package org.springframework.cloud.consul.config; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; - import java.util.Random; import com.ecwid.consul.v1.ConsulClient; - import org.junit.After; import org.junit.Before; import org.junit.Test; + import org.springframework.cloud.consul.ConsulProperties; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Spencer Gibb */ public class ConsulPropertySourceTests { private ConsulClient client; + private ConsulProperties properties; + private String prefix; + private String kvContext; + private String propertiesContext; @Before public void setup() { - properties = new ConsulProperties(); - prefix = "consulPropertySourceTests" + new Random().nextInt(Integer.MAX_VALUE); - client = new ConsulClient(properties.getHost(), properties.getPort()); + this.properties = new ConsulProperties(); + this.prefix = "consulPropertySourceTests" + + new Random().nextInt(Integer.MAX_VALUE); + this.client = new ConsulClient(this.properties.getHost(), + this.properties.getPort()); } @After public void teardown() { - client.deleteKVValues(prefix); + this.client.deleteKVValues(this.prefix); } @Test public void testKv() { // key value properties - kvContext = prefix + "/kv"; - client.setKVValue(kvContext + "/fooprop", "fookvval"); - client.setKVValue(prefix+"/kv"+"/bar/prop", "8080"); + this.kvContext = this.prefix + "/kv"; + this.client.setKVValue(this.kvContext + "/fooprop", "fookvval"); + this.client.setKVValue(this.prefix + "/kv" + "/bar/prop", "8080"); - ConsulPropertySource source = getConsulPropertySource(new ConsulConfigProperties(), kvContext); + ConsulPropertySource source = getConsulPropertySource( + new ConsulConfigProperties(), this.kvContext); assertProperties(source, "fookvval", "8080"); } - private void assertProperties(ConsulPropertySource source, Object fooval, Object barval) { - assertThat("fooprop was wrong", source.getProperty("fooprop"), is(equalTo(fooval))); - assertThat("bar.prop was wrong", source.getProperty("bar.prop"), is(equalTo(barval))); + private void assertProperties(ConsulPropertySource source, Object fooval, + Object barval) { + assertThat(source.getProperty("fooprop")).as("fooprop was wrong") + .isEqualTo(fooval); + assertThat(source.getProperty("bar.prop")).as("bar.prop was wrong") + .isEqualTo(barval); } @Test public void testProperties() { // properties file property - propertiesContext = prefix + "/properties"; - client.setKVValue(propertiesContext+"/data", "fooprop=foopropval\nbar.prop=8080"); + this.propertiesContext = this.prefix + "/properties"; + this.client.setKVValue(this.propertiesContext + "/data", + "fooprop=foopropval\nbar.prop=8080"); ConsulConfigProperties configProperties = new ConsulConfigProperties(); configProperties.setFormat(ConsulConfigProperties.Format.PROPERTIES); - ConsulPropertySource source = getConsulPropertySource(configProperties, propertiesContext); + ConsulPropertySource source = getConsulPropertySource(configProperties, + this.propertiesContext); assertProperties(source, "foopropval", "8080"); } @@ -84,12 +95,14 @@ public class ConsulPropertySourceTests { @Test public void testYaml() { // yaml file property - String yamlContext = prefix + "/yaml"; - client.setKVValue(yamlContext+"/data", "fooprop: fooymlval\nbar:\n prop: 8080"); + String yamlContext = this.prefix + "/yaml"; + this.client.setKVValue(yamlContext + "/data", + "fooprop: fooymlval\nbar:\n prop: 8080"); ConsulConfigProperties configProperties = new ConsulConfigProperties(); configProperties.setFormat(ConsulConfigProperties.Format.YAML); - ConsulPropertySource source = getConsulPropertySource(configProperties, yamlContext); + ConsulPropertySource source = getConsulPropertySource(configProperties, + yamlContext); assertProperties(source, "fooymlval", 8080); } @@ -97,22 +110,26 @@ public class ConsulPropertySourceTests { @Test public void testEmptyYaml() { // yaml file property - String yamlContext = prefix + "/yaml"; - client.setKVValue(yamlContext+"/data", ""); + String yamlContext = this.prefix + "/yaml"; + this.client.setKVValue(yamlContext + "/data", ""); ConsulConfigProperties configProperties = new ConsulConfigProperties(); configProperties.setFormat(ConsulConfigProperties.Format.YAML); - ConsulPropertySource source = new ConsulPropertySource(yamlContext, client, configProperties); + ConsulPropertySource source = new ConsulPropertySource(yamlContext, this.client, + configProperties); // Should NOT throw a NPE source.init(); } - private ConsulPropertySource getConsulPropertySource(ConsulConfigProperties configProperties, String context) { - ConsulPropertySource source = new ConsulPropertySource(context, client, configProperties); + private ConsulPropertySource getConsulPropertySource( + ConsulConfigProperties configProperties, String context) { + ConsulPropertySource source = new ConsulPropertySource(context, this.client, + configProperties); source.init(); String[] names = source.getPropertyNames(); - assertThat("names was null", names, is(notNullValue())); - assertThat("names was wrong size", names.length, is(equalTo(2))); + assertThat(names).as("names was null").isNotNull(); + assertThat(names.length).as("names was wrong size").isEqualTo(2); return source; } + } diff --git a/spring-cloud-consul-core/pom.xml b/spring-cloud-consul-core/pom.xml index 1e8b8870..3067dd8a 100644 --- a/spring-cloud-consul-core/pom.xml +++ b/spring-cloud-consul-core/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConditionalOnConsulEnabled.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConditionalOnConsulEnabled.java index 192973ff..f87219fe 100644 --- a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConditionalOnConsulEnabled.java +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConditionalOnConsulEnabled.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,26 +22,46 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.ecwid.consul.v1.ConsulClient; + import org.springframework.boot.autoconfigure.condition.AllNestedConditions; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Conditional; +/** + * When both property and consul classes are on the classpath. + * @author Spencer Gibb + */ @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE, ElementType.METHOD}) +@Target({ ElementType.TYPE, ElementType.METHOD }) @Conditional(ConditionalOnConsulEnabled.OnConsulEnabledCondition.class) public @interface ConditionalOnConsulEnabled { + /** + * Verifies multiple conditions to see if Consul should be enabled. + */ class OnConsulEnabledCondition extends AllNestedConditions { - public OnConsulEnabledCondition() { + OnConsulEnabledCondition() { super(ConfigurationPhase.REGISTER_BEAN); } + /** + * Consul property is enabled. + */ @ConditionalOnProperty(value = "spring.cloud.consul.enabled", matchIfMissing = true) - static class FoundProperty {} + static class FoundProperty { + } + + /** + * Consul client class found. + */ @ConditionalOnClass(ConsulClient.class) - static class FoundClass {} + static class FoundClass { + + } + } + } diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulAutoConfiguration.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulAutoConfiguration.java index 67190553..752e7e42 100644 --- a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulAutoConfiguration.java +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.cloud.consul; import com.ecwid.consul.transport.TLSConfig; import com.ecwid.consul.v1.ConsulClient; import org.aspectj.lang.annotation.Aspect; + import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -33,8 +34,6 @@ import org.springframework.retry.annotation.EnableRetry; import org.springframework.retry.annotation.Retryable; import org.springframework.retry.interceptor.RetryInterceptorBuilder; import org.springframework.retry.interceptor.RetryOperationsInterceptor; - -import com.ecwid.consul.v1.ConsulClient; import org.springframework.util.StringUtils; /** @@ -61,13 +60,9 @@ public class ConsulAutoConfiguration { if (consulProperties.getTls() != null) { ConsulProperties.TLSConfig tls = consulProperties.getTls(); - TLSConfig tlsConfig = new TLSConfig( - tls.getKeyStoreInstanceType(), - tls.getCertificatePath(), - tls.getCertificatePassword(), - tls.getKeyStorePath(), - tls.getKeyStorePassword() - ); + TLSConfig tlsConfig = new TLSConfig(tls.getKeyStoreInstanceType(), + tls.getCertificatePath(), tls.getCertificatePassword(), + tls.getKeyStorePath(), tls.getKeyStorePassword()); return new ConsulClient(agentHost, agentPort, tlsConfig); } return new ConsulClient(agentHost, agentPort); @@ -90,6 +85,7 @@ public class ConsulAutoConfiguration { public ConsulHealthIndicator consulHealthIndicator(ConsulClient consulClient) { return new ConsulHealthIndicator(consulClient); } + } @ConditionalOnClass({ Retryable.class, Aspect.class, AopAutoConfiguration.class }) @@ -103,11 +99,12 @@ public class ConsulAutoConfiguration { @ConditionalOnMissingBean(name = "consulRetryInterceptor") public RetryOperationsInterceptor consulRetryInterceptor( RetryProperties properties) { - return RetryInterceptorBuilder - .stateless() + return RetryInterceptorBuilder.stateless() .backOffOptions(properties.getInitialInterval(), properties.getMultiplier(), properties.getMaxInterval()) .maxAttempts(properties.getMaxAttempts()).build(); } + } + } diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulEndpoint.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulEndpoint.java index a17711a9..fa3953ab 100644 --- a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulEndpoint.java +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,25 +47,30 @@ public class ConsulEndpoint { public ConsulData invoke() { ConsulData data = new ConsulData(); // data.setKeyValues(kvClient.getKeyValueRecurse()); - Response> agentServices = consul.getAgentServices(); + Response> agentServices = this.consul.getAgentServices(); data.setAgentServices(agentServices.getValue()); - Response>> catalogServices = consul + Response>> catalogServices = this.consul .getCatalogServices(QueryParams.DEFAULT); for (String serviceId : catalogServices.getValue().keySet()) { - Response> response = consul.getCatalogService(serviceId, - QueryParams.DEFAULT); + Response> response = this.consul + .getCatalogService(serviceId, QueryParams.DEFAULT); data.getCatalogServices().put(serviceId, response.getValue()); } - Response> catalogNodes = consul.getCatalogNodes(QueryParams.DEFAULT); + Response> catalogNodes = this.consul + .getCatalogNodes(QueryParams.DEFAULT); data.setCatalogNodes(catalogNodes.getValue()); return data; } + /** + * Represents Consul data related to catalog entries and agent servies. + */ public static class ConsulData { + Map> catalogServices = new LinkedHashMap<>(); Map agentServices; @@ -79,22 +84,23 @@ public class ConsulEndpoint { return this.catalogServices; } + public void setCatalogServices( + Map> catalogServices) { + this.catalogServices = catalogServices; + } + public Map getAgentServices() { return this.agentServices; } - public List getCatalogNodes() { - return this.catalogNodes; - } - - public void setCatalogServices(Map> catalogServices) { - this.catalogServices = catalogServices; - } - public void setAgentServices(Map agentServices) { this.agentServices = agentServices; } + public List getCatalogNodes() { + return this.catalogNodes; + } + public void setCatalogNodes(List catalogNodes) { this.catalogNodes = catalogNodes; } @@ -102,10 +108,11 @@ public class ConsulEndpoint { @Override public String toString() { return new ToStringCreator(this) - .append("catalogServices", catalogServices) - .append("agentServices", agentServices) - .append("catalogNodes", catalogNodes) - .toString(); + .append("catalogServices", this.catalogServices) + .append("agentServices", this.agentServices) + .append("catalogNodes", this.catalogNodes).toString(); } + } + } diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicator.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicator.java index 36fa103c..69f000d4 100644 --- a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicator.java +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulHealthIndicator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,13 +19,13 @@ package org.springframework.cloud.consul; import java.util.List; import java.util.Map; -import org.springframework.boot.actuate.health.AbstractHealthIndicator; -import org.springframework.boot.actuate.health.Health; - import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.QueryParams; import com.ecwid.consul.v1.Response; +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; + /** * @author Spencer Gibb */ @@ -39,10 +39,11 @@ public class ConsulHealthIndicator extends AbstractHealthIndicator { @Override protected void doHealthCheck(Health.Builder builder) throws Exception { - final Response leaderStatus = consul.getStatusLeader(); - final Response>> services = consul + final Response leaderStatus = this.consul.getStatusLeader(); + final Response>> services = this.consul .getCatalogServices(QueryParams.DEFAULT); builder.up().withDetail("leader", leaderStatus.getValue()).withDetail("services", services.getValue()); } + } diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulProperties.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulProperties.java index f8dad7cc..24494537 100644 --- a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulProperties.java +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/ConsulProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,26 +30,29 @@ import org.springframework.validation.annotation.Validated; @ConfigurationProperties("spring.cloud.consul") @Validated public class ConsulProperties { + /** Consul agent hostname. Defaults to 'localhost'. */ @NotNull private String host = "localhost"; - /** Consul agent scheme (HTTP/HTTPS). If there is no scheme in address - client will use HTTP. */ + /** + * Consul agent scheme (HTTP/HTTPS). If there is no scheme in address - client will + * use HTTP. + */ private String scheme; /** Consul agent port. Defaults to '8500'. */ @NotNull private int port = 8500; - /** Is spring cloud consul enabled */ + /** Is spring cloud consul enabled. */ private boolean enabled = true; - /** configuration for TLS */ + /** configuration for TLS. */ private TLSConfig tls; - public String getHost() { - return host; + return this.host; } public void setHost(String host) { @@ -57,7 +60,7 @@ public class ConsulProperties { } public int getPort() { - return port; + return this.port; } public void setPort(int port) { @@ -65,7 +68,7 @@ public class ConsulProperties { } public boolean isEnabled() { - return enabled; + return this.enabled; } public void setEnabled(boolean enabled) { @@ -73,7 +76,7 @@ public class ConsulProperties { } public String getScheme() { - return scheme; + return this.scheme; } public void setScheme(String scheme) { @@ -81,7 +84,7 @@ public class ConsulProperties { } public TLSConfig getTls() { - return tls; + return this.tls; } public void setTls(TLSConfig tls) { @@ -90,26 +93,26 @@ public class ConsulProperties { @Override public String toString() { - return "ConsulProperties{" + - "host='" + host + '\'' + - ", port=" + port + - ", scheme=" + scheme + - ", tls=" + tls + - ", enabled=" + enabled + - '}'; + return "ConsulProperties{" + "host='" + this.host + '\'' + ", port=" + this.port + + ", scheme=" + this.scheme + ", tls=" + this.tls + ", enabled=" + + this.enabled + '}'; } + /** + * TLS configuration. + */ public static class TLSConfig { + /** Type of key framework to use. */ private KeyStoreInstanceType keyStoreInstanceType; - /** Path to an external keystore */ + /** Path to an external keystore. */ private String keyStorePath; - /** Password to an external keystore */ + /** Password to an external keystore. */ private String keyStorePassword; - /**File path to the certificate. */ + /** File path to the certificate. */ private String certificatePath; /** Password to open the certificate. */ @@ -118,7 +121,9 @@ public class ConsulProperties { public TLSConfig() { } - public TLSConfig(KeyStoreInstanceType keyStoreInstanceType, String keyStorePath, String keyStorePassword, String certificatePath, String certificatePassword) { + public TLSConfig(KeyStoreInstanceType keyStoreInstanceType, String keyStorePath, + String keyStorePassword, String certificatePath, + String certificatePassword) { this.keyStoreInstanceType = keyStoreInstanceType; this.keyStorePath = keyStorePath; this.keyStorePassword = keyStorePassword; @@ -127,7 +132,7 @@ public class ConsulProperties { } public KeyStoreInstanceType getKeyStoreInstanceType() { - return keyStoreInstanceType; + return this.keyStoreInstanceType; } public void setKeyStoreInstanceType(KeyStoreInstanceType keyStoreInstanceType) { @@ -135,7 +140,7 @@ public class ConsulProperties { } public String getKeyStorePath() { - return keyStorePath; + return this.keyStorePath; } public void setKeyStorePath(String keyStorePath) { @@ -143,7 +148,7 @@ public class ConsulProperties { } public String getKeyStorePassword() { - return keyStorePassword; + return this.keyStorePassword; } public void setKeyStorePassword(String keyStorePassword) { @@ -151,7 +156,7 @@ public class ConsulProperties { } public String getCertificatePath() { - return certificatePath; + return this.certificatePath; } public void setCertificatePath(String certificatePath) { @@ -159,7 +164,7 @@ public class ConsulProperties { } public String getCertificatePassword() { - return certificatePassword; + return this.certificatePassword; } public void setCertificatePassword(String certificatePassword) { @@ -169,12 +174,13 @@ public class ConsulProperties { @Override public String toString() { return new ToStringCreator(this) - .append("keyStoreInstanceType", keyStoreInstanceType) - .append("keyStorePath", keyStorePath) - .append("keyStorePassword", keyStorePassword) - .append("certificatePath", certificatePath) - .append("certificatePassword", certificatePassword) - .toString(); + .append("keyStoreInstanceType", this.keyStoreInstanceType) + .append("keyStorePath", this.keyStorePath) + .append("keyStorePassword", this.keyStorePassword) + .append("certificatePath", this.certificatePath) + .append("certificatePassword", this.certificatePassword).toString(); } + } + } diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/RetryProperties.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/RetryProperties.java index d371b0f8..2910e80c 100644 --- a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/RetryProperties.java +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/RetryProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,41 +44,40 @@ public class RetryProperties { return this.initialInterval; } - public double getMultiplier() { - return this.multiplier; - } - - public long getMaxInterval() { - return this.maxInterval; - } - - public int getMaxAttempts() { - return this.maxAttempts; - } - public void setInitialInterval(long initialInterval) { this.initialInterval = initialInterval; } + public double getMultiplier() { + return this.multiplier; + } + public void setMultiplier(double multiplier) { this.multiplier = multiplier; } + public long getMaxInterval() { + return this.maxInterval; + } + public void setMaxInterval(long maxInterval) { this.maxInterval = maxInterval; } + public int getMaxAttempts() { + return this.maxAttempts; + } + public void setMaxAttempts(int maxAttempts) { this.maxAttempts = maxAttempts; } @Override public String toString() { - return new ToStringCreator(this) - .append("initialInterval", initialInterval) - .append("multiplier", multiplier) - .append("maxInterval", maxInterval) - .append("maxAttempts", maxAttempts) - .toString(); + return new ToStringCreator(this).append("initialInterval", this.initialInterval) + .append("multiplier", this.multiplier) + .append("maxInterval", this.maxInterval) + .append("maxAttempts", this.maxAttempts).toString(); } + } diff --git a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/model/SerfStatusEnum.java b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/model/SerfStatusEnum.java index d6e5982e..0aece88c 100644 --- a/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/model/SerfStatusEnum.java +++ b/spring-cloud-consul-core/src/main/java/org/springframework/cloud/consul/model/SerfStatusEnum.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,30 @@ package org.springframework.cloud.consul.model; /** * Gossip pool (serf) statuses. Created by nicu on 10.03.2015. + * @author Nicu Marasoiu */ public enum SerfStatusEnum { - StatusAlive(1), StatusLeaving(2), StatusLeft(3), StatusFailed(4); + + /** + * Alive status. + */ + StatusAlive(1), + + /** + * Leaving status. + */ + StatusLeaving(2), + + /** + * Left status. + */ + StatusLeft(3), + + /** + * Failed status. + */ + StatusFailed(4); + private final int code; SerfStatusEnum(int code) { @@ -28,7 +49,7 @@ public enum SerfStatusEnum { } public int getCode() { - return code; + return this.code; } } diff --git a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulAutoConfigurationTests.java b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulAutoConfigurationTests.java index fe226ba1..25df08e0 100644 --- a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulAutoConfigurationTests.java +++ b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulAutoConfigurationTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.consul; import com.ecwid.consul.transport.DefaultHttpsTransport; @@ -18,11 +34,11 @@ import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) -@SpringBootTest(properties = {"spring.cloud.consul.tls.key-store-instance-type=JKS", +@SpringBootTest(properties = { "spring.cloud.consul.tls.key-store-instance-type=JKS", "spring.cloud.consul.tls.key-store-path=src/test/resources/server.jks", "spring.cloud.consul.tls.key-store-password=letmein", "spring.cloud.consul.tls.certificate-path=src/test/resources/trustStore.jks", - "spring.cloud.consul.tls.certificate-password=change_me", }) + "spring.cloud.consul.tls.certificate-password=change_me" }) public class ConsulAutoConfigurationTests { @Autowired @@ -30,13 +46,19 @@ public class ConsulAutoConfigurationTests { @Test public void tlsConfigured() { - CatalogConsulClient client = (CatalogConsulClient) ReflectionTestUtils.getField(consulClient, "catalogClient"); - ConsulRawClient rawClient = (ConsulRawClient) ReflectionTestUtils.getField(client, "rawClient"); - HttpTransport httpTransport = (HttpTransport) ReflectionTestUtils.getField(rawClient, "httpTransport"); + CatalogConsulClient client = (CatalogConsulClient) ReflectionTestUtils + .getField(this.consulClient, "catalogClient"); + ConsulRawClient rawClient = (ConsulRawClient) ReflectionTestUtils.getField(client, + "rawClient"); + HttpTransport httpTransport = (HttpTransport) ReflectionTestUtils + .getField(rawClient, "httpTransport"); assertThat(httpTransport).isInstanceOf(DefaultHttpsTransport.class); } @EnableAutoConfiguration @SpringBootConfiguration - protected static class TestConfig {} + protected static class TestConfig { + + } + } diff --git a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorDownTest.java b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorDownTest.java index 969251fe..8b640c2c 100644 --- a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorDownTest.java +++ b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorDownTest.java @@ -1,9 +1,24 @@ -package org.springframework.cloud.consul; +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import static org.junit.Assert.assertEquals; +package org.springframework.cloud.consul; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.actuate.health.HealthEndpoint; @@ -12,6 +27,8 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Lomesh Patel (lomeshpatel) */ @@ -24,12 +41,14 @@ public class ConsulHealthIndicatorDownTest { @Test public void doHealthCheck() { - assertEquals("health status was not DOWN", Status.DOWN, - healthEndpoint.health().getStatus()); + assertThat(this.healthEndpoint.health().getStatus()) + .as("health status was not DOWN").isEqualTo(Status.DOWN); } @EnableAutoConfiguration @SpringBootConfiguration protected static class TestConfig { + } -} \ No newline at end of file + +} diff --git a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorUpTest.java b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorUpTest.java index 503422cf..df898786 100644 --- a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorUpTest.java +++ b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/ConsulHealthIndicatorUpTest.java @@ -1,9 +1,24 @@ -package org.springframework.cloud.consul; +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import static org.junit.Assert.assertEquals; +package org.springframework.cloud.consul; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.actuate.health.HealthEndpoint; @@ -12,6 +27,8 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Lomesh Patel (lomeshpatel) */ @@ -24,12 +41,14 @@ public class ConsulHealthIndicatorUpTest { @Test public void doHealthCheck() { - assertEquals("health status was not UP", Status.UP, - healthEndpoint.health().getStatus()); + assertThat(this.healthEndpoint.health().getStatus()) + .as("health status was not UP").isEqualTo(Status.UP); } @EnableAutoConfiguration @SpringBootConfiguration protected static class TestConfig { + } -} \ No newline at end of file + +} diff --git a/spring-cloud-consul-dependencies/pom.xml b/spring-cloud-consul-dependencies/pom.xml index 061fb4cd..4a841829 100644 --- a/spring-cloud-consul-dependencies/pom.xml +++ b/spring-cloud-consul-dependencies/pom.xml @@ -1,12 +1,13 @@ - 4.0.0 spring-cloud-dependencies-parent org.springframework.cloud 2.1.3.BUILD-SNAPSHOT - + spring-cloud-consul-dependencies 2.1.1.BUILD-SNAPSHOT diff --git a/spring-cloud-consul-discovery/pom.xml b/spring-cloud-consul-discovery/pom.xml index 358f96aa..f4036bb0 100644 --- a/spring-cloud-consul-discovery/pom.xml +++ b/spring-cloud-consul-discovery/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulCatalogWatch.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulCatalogWatch.java index a8f04561..c8121aa8 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulCatalogWatch.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulCatalogWatch.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,20 +40,35 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; /** * @author Spencer Gibb */ -public class ConsulCatalogWatch implements ApplicationEventPublisherAware, SmartLifecycle { +public class ConsulCatalogWatch + implements ApplicationEventPublisherAware, SmartLifecycle { + private static final Log log = LogFactory.getLog(ConsulDiscoveryClient.class); private final ConsulDiscoveryProperties properties; + private final ConsulClient consul; + private final TaskScheduler taskScheduler; + private final AtomicReference catalogServicesIndex = new AtomicReference<>(); + private final AtomicBoolean running = new AtomicBoolean(false); + private ApplicationEventPublisher publisher; + private ScheduledFuture watchFuture; public ConsulCatalogWatch(ConsulDiscoveryProperties properties, ConsulClient consul) { this(properties, consul, getTaskScheduler()); - } + } + + public ConsulCatalogWatch(ConsulDiscoveryProperties properties, ConsulClient consul, + TaskScheduler taskScheduler) { + this.properties = properties; + this.consul = consul; + this.taskScheduler = taskScheduler; + } private static ThreadPoolTaskScheduler getTaskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); @@ -61,12 +76,6 @@ public class ConsulCatalogWatch implements ApplicationEventPublisherAware, Smart return taskScheduler; } - public ConsulCatalogWatch(ConsulDiscoveryProperties properties, ConsulClient consul, TaskScheduler taskScheduler) { - this.properties = properties; - this.consul = consul; - this.taskScheduler = taskScheduler; - } - @Override public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; @@ -86,7 +95,8 @@ public class ConsulCatalogWatch implements ApplicationEventPublisherAware, Smart @Override public void start() { if (this.running.compareAndSet(false, true)) { - this.watchFuture = this.taskScheduler.scheduleWithFixedDelay(this::catalogServicesWatch, + this.watchFuture = this.taskScheduler.scheduleWithFixedDelay( + this::catalogServicesWatch, this.properties.getCatalogServicesWatchDelay()); } } @@ -108,30 +118,32 @@ public class ConsulCatalogWatch implements ApplicationEventPublisherAware, Smart return 0; } - @Timed(value ="consul.watch-catalog-services") + @Timed("consul.watch-catalog-services") public void catalogServicesWatch() { try { long index = -1; - if (catalogServicesIndex.get() != null) { - index = catalogServicesIndex.get().longValue(); + if (this.catalogServicesIndex.get() != null) { + index = this.catalogServicesIndex.get().longValue(); } - Response>> response = consul - .getCatalogServices(new QueryParams(properties - .getCatalogServicesWatchTimeout(), index), properties.getAclToken()); + Response>> response = this.consul.getCatalogServices( + new QueryParams(this.properties.getCatalogServicesWatchTimeout(), + index), + this.properties.getAclToken()); Long consulIndex = response.getConsulIndex(); if (consulIndex != null) { - catalogServicesIndex.set(BigInteger.valueOf(consulIndex)); + this.catalogServicesIndex.set(BigInteger.valueOf(consulIndex)); } if (log.isTraceEnabled()) { - log.trace("Received services update from consul: "+response.getValue() - +", index: "+ consulIndex); + log.trace("Received services update from consul: " + response.getValue() + + ", index: " + consulIndex); } - publisher.publishEvent(new HeartbeatEvent(this, consulIndex)); + this.publisher.publishEvent(new HeartbeatEvent(this, consulIndex)); } catch (Exception e) { log.error("Error watching Consul CatalogServices", e); } } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClient.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClient.java index ec0d51cf..cbaea910 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClient.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,16 +44,12 @@ public class ConsulDiscoveryClient implements DiscoveryClient { private static final Log log = LogFactory.getLog(ConsulDiscoveryClient.class); - @Deprecated - public interface LocalResolver { - String getInstanceId(); - Integer getPort(); - } - private final ConsulClient client; + private final ConsulDiscoveryProperties properties; - public ConsulDiscoveryClient(ConsulClient client, ConsulDiscoveryProperties properties) { + public ConsulDiscoveryClient(ConsulClient client, + ConsulDiscoveryProperties properties) { this.client = client; this.properties = properties; } @@ -80,15 +76,15 @@ public class ConsulDiscoveryClient implements DiscoveryClient { private void addInstancesToList(List instances, String serviceId, QueryParams queryParams) { - String aclToken = properties.getAclToken(); + String aclToken = this.properties.getAclToken(); Response> services; if (StringUtils.hasText(aclToken)) { - services = client.getHealthServices(serviceId, + services = this.client.getHealthServices(serviceId, this.properties.getDefaultQueryTag(), this.properties.isQueryPassing(), queryParams, aclToken); } else { - services = client.getHealthServices(serviceId, + services = this.client.getHealthServices(serviceId, this.properties.getDefaultQueryTag(), this.properties.isQueryPassing(), queryParams); } @@ -100,15 +96,15 @@ public class ConsulDiscoveryClient implements DiscoveryClient { if (metadata.containsKey("secure")) { secure = Boolean.parseBoolean(metadata.get("secure")); } - instances.add(new DefaultServiceInstance(service.getService().getId(), serviceId, host, service - .getService().getPort(), secure, metadata)); + instances.add(new DefaultServiceInstance(service.getService().getId(), + serviceId, host, service.getService().getPort(), secure, metadata)); } } public List getAllInstances() { List instances = new ArrayList<>(); - Response>> services = client + Response>> services = this.client .getCatalogServices(QueryParams.DEFAULT); for (String serviceId : services.getValue().keySet()) { addInstancesToList(instances, serviceId, QueryParams.DEFAULT); @@ -118,14 +114,16 @@ public class ConsulDiscoveryClient implements DiscoveryClient { @Override public List getServices() { - String aclToken = properties.getAclToken(); + String aclToken = this.properties.getAclToken(); if (StringUtils.hasText(aclToken)) { - return new ArrayList<>(client.getCatalogServices(QueryParams.DEFAULT, aclToken).getValue() - .keySet()); - } else { - return new ArrayList<>(client.getCatalogServices(QueryParams.DEFAULT).getValue() - .keySet()); + return new ArrayList<>( + this.client.getCatalogServices(QueryParams.DEFAULT, aclToken) + .getValue().keySet()); + } + else { + return new ArrayList<>(this.client.getCatalogServices(QueryParams.DEFAULT) + .getValue().keySet()); } } @@ -133,4 +131,17 @@ public class ConsulDiscoveryClient implements DiscoveryClient { public int getOrder() { return this.properties.getOrder(); } + + /** + * Depreacted local resolver. + */ + @Deprecated + public interface LocalResolver { + + String getInstanceId(); + + Integer getPort(); + + } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientConfiguration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientConfiguration.java index fcdb6e97..1a4ed37f 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientConfiguration.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,9 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; CommonsClientAutoConfiguration.class }) public class ConsulDiscoveryClientConfiguration { + /** + * Name of the catalog watch task scheduler bean. + */ public static final String CATALOG_WATCH_TASK_SCHEDULER_NAME = "catalogWatchTaskScheduler"; @Autowired @@ -53,29 +56,30 @@ public class ConsulDiscoveryClientConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnProperty("spring.cloud.consul.discovery.heartbeat.enabled") - //TODO: move to service-registry for Edgware + // TODO: move to service-registry for Edgware public TtlScheduler ttlScheduler(HeartbeatProperties heartbeatProperties) { - return new TtlScheduler(heartbeatProperties, consulClient); + return new TtlScheduler(heartbeatProperties, this.consulClient); } @Bean @ConditionalOnMissingBean - //TODO: move to service-registry for Edgware + // TODO: move to service-registry for Edgware public HeartbeatProperties heartbeatProperties() { return new HeartbeatProperties(); } @Bean @ConditionalOnMissingBean - //TODO: Split appropriate values to service-registry for Edgware + // TODO: Split appropriate values to service-registry for Edgware public ConsulDiscoveryProperties consulDiscoveryProperties(InetUtils inetUtils) { return new ConsulDiscoveryProperties(inetUtils); } @Bean @ConditionalOnMissingBean - public ConsulDiscoveryClient consulDiscoveryClient(ConsulDiscoveryProperties discoveryProperties) { - return new ConsulDiscoveryClient(consulClient, discoveryProperties); + public ConsulDiscoveryClient consulDiscoveryClient( + ConsulDiscoveryProperties discoveryProperties) { + return new ConsulDiscoveryClient(this.consulClient, discoveryProperties); } @Bean @@ -84,7 +88,8 @@ public class ConsulDiscoveryClientConfiguration { public ConsulCatalogWatch consulCatalogWatch( ConsulDiscoveryProperties discoveryProperties, @Qualifier(CATALOG_WATCH_TASK_SCHEDULER_NAME) TaskScheduler taskScheduler) { - return new ConsulCatalogWatch(discoveryProperties, consulClient, taskScheduler); + return new ConsulCatalogWatch(discoveryProperties, this.consulClient, + taskScheduler); } @Bean(name = CATALOG_WATCH_TASK_SCHEDULER_NAME) @@ -92,4 +97,5 @@ public class ConsulDiscoveryClientConfiguration { public TaskScheduler catalogWatchTaskScheduler() { return new ThreadPoolTaskScheduler(); } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryProperties.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryProperties.java index 1ae49fb7..1ac893f4 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryProperties.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,17 @@ package org.springframework.cloud.consul.discovery; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.commons.util.InetUtils.HostInfo; import org.springframework.core.style.ToStringCreator; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * Defines configuration for service discovery and registration. * @@ -45,22 +45,22 @@ public class ConsulDiscoveryProperties { @Value("${consul.token:${CONSUL_TOKEN:${spring.cloud.consul.token:${SPRING_CLOUD_CONSUL_TOKEN:}}}}") private String aclToken; - /** Tags to use when registering service */ + /** Tags to use when registering service. */ private List tags = new ArrayList<>(); /** Is service discovery enabled? */ private boolean enabled = true; - /** Tags to use when registering management service */ + /** Tags to use when registering management service. */ private List managementTags = new ArrayList<>(); - /** Alternate server path to invoke for health checking */ + /** Alternate server path to invoke for health checking. */ private String healthCheckPath = "/actuator/health"; - /** Custom health check url to override default */ + /** Custom health check url to override default. */ private String healthCheckUrl; - /** Headers to be applied to the Health Check calls */ + /** Headers to be applied to the Health Check calls. */ private Map> healthCheckHeaders = new HashMap<>(); /** How often to perform the health check (e.g. 10s), defaults to 10s. */ @@ -75,24 +75,26 @@ public class ConsulDiscoveryProperties { */ private String healthCheckCriticalTimeout; - /** IP address to use when accessing service (must also set preferIpAddress to use) */ + /** + * IP address to use when accessing service (must also set preferIpAddress to use). + */ private String ipAddress; - /** Hostname to use when accessing server */ + /** Hostname to use when accessing server. */ private String hostname; - /** Port to register the service under (defaults to listening port) */ + /** Port to register the service under (defaults to listening port). */ private Integer port; - /** Port to register the management service under (defaults to management port) */ + /** Port to register the management service under (defaults to management port). */ private Integer managementPort; private Lifecycle lifecycle = new Lifecycle(); - /** Use ip address rather than hostname during registration */ + /** Use ip address rather than hostname during registration. */ private boolean preferIpAddress = false; - /** Source of how we will determine the address to use */ + /** Source of how we will determine the address to use. */ private boolean preferAgentAddress = false; /** The delay between calls to watch consul catalog in millis, default is 1000. */ @@ -101,40 +103,39 @@ public class ConsulDiscoveryProperties { /** The number of seconds to block while watching consul catalog, default is 2. */ private int catalogServicesWatchTimeout = 2; - /** Service name */ + /** Service name. */ private String serviceName; - /** Unique service instance id */ + /** Unique service instance id. */ private String instanceId; - /** Service instance zone */ + /** Service instance zone. */ private String instanceZone; - /** Service instance group*/ + /** Service instance group. */ private String instanceGroup; - /** - * Service instance zone comes from metadata. - * This allows changing the metadata tag name. + * Service instance zone comes from metadata. This allows changing the metadata tag + * name. */ private String defaultZoneMetadataName = "zone"; - /** Whether to register an http or https service */ + /** Whether to register an http or https service. */ private String scheme = "http"; - /** Suffix to use when registering management service */ + /** Suffix to use when registering management service. */ private String managementSuffix = MANAGEMENT; /** - * Map of serviceId's -> tag to query for in server list. - * This allows filtering services by a single tag. + * Map of serviceId's -> tag to query for in server list. This allows filtering + * services by a single tag. */ private Map serverListQueryTags = new HashMap<>(); /** - * Map of serviceId's -> datacenter to query for in server list. - * This allows looking up services in another datacenters. + * Map of serviceId's -> datacenter to query for in server list. This allows looking + * up services in another datacenters. */ private Map datacenters = new HashMap<>(); @@ -142,8 +143,8 @@ public class ConsulDiscoveryProperties { private String defaultQueryTag; /** - * Add the 'passing` parameter to /v1/health/service/serviceName. - * This pushes health check passing to the server. + * Add the 'passing` parameter to /v1/health/service/serviceName. This pushes health + * check passing to the server. */ private boolean queryPassing = false; @@ -157,19 +158,20 @@ public class ConsulDiscoveryProperties { private boolean registerHealthCheck = true; /** - * Throw exceptions during service registration if true, otherwise, log - * warnings (defaults to true). + * Throw exceptions during service registration if true, otherwise, log warnings + * (defaults to true). */ private boolean failFast = true; /** - * Skips certificate verification during service checks if true, otherwise - * runs certificate verification. + * Skips certificate verification during service checks if true, otherwise runs + * certificate verification. */ private Boolean healthCheckTlsSkipVerify; /** - * Order of the discovery client used by `CompositeDiscoveryClient` for sorting available clients. + * Order of the discovery client used by `CompositeDiscoveryClient` for sorting + * available clients. */ private int order = 0; @@ -189,9 +191,9 @@ public class ConsulDiscoveryProperties { * @param serviceId The service who's filtering tag is being looked up * @return The tag the given service id should be filtered by, or null. */ - public String getQueryTagForService(String serviceId){ - String tag = serverListQueryTags.get(serviceId); - return tag != null ? tag : defaultQueryTag; + public String getQueryTagForService(String serviceId) { + String tag = this.serverListQueryTags.get(serviceId); + return tag != null ? tag : this.defaultQueryTag; } public String getHostname() { @@ -203,13 +205,8 @@ public class ConsulDiscoveryProperties { this.hostInfo.override = true; } - public void setIpAddress(String ipAddress) { - this.ipAddress = ipAddress; - this.hostInfo.override = true; - } - private HostInfo getHostInfo() { - return hostInfo; + return this.hostInfo; } private void setHostInfo(HostInfo hostInfo) { @@ -217,7 +214,7 @@ public class ConsulDiscoveryProperties { } public String getAclToken() { - return aclToken; + return this.aclToken; } public void setAclToken(String aclToken) { @@ -225,7 +222,7 @@ public class ConsulDiscoveryProperties { } public List getTags() { - return tags; + return this.tags; } public void setTags(List tags) { @@ -233,7 +230,7 @@ public class ConsulDiscoveryProperties { } public boolean isEnabled() { - return enabled; + return this.enabled; } public void setEnabled(boolean enabled) { @@ -241,7 +238,7 @@ public class ConsulDiscoveryProperties { } public List getManagementTags() { - return managementTags; + return this.managementTags; } public void setManagementTags(List managementTags) { @@ -249,7 +246,7 @@ public class ConsulDiscoveryProperties { } public String getHealthCheckPath() { - return healthCheckPath; + return this.healthCheckPath; } public void setHealthCheckPath(String healthCheckPath) { @@ -257,7 +254,7 @@ public class ConsulDiscoveryProperties { } public String getHealthCheckUrl() { - return healthCheckUrl; + return this.healthCheckUrl; } public void setHealthCheckUrl(String healthCheckUrl) { @@ -265,7 +262,7 @@ public class ConsulDiscoveryProperties { } public Map> getHealthCheckHeaders() { - return healthCheckHeaders; + return this.healthCheckHeaders; } public void setHealthCheckHeaders(Map> healthCheckHeaders) { @@ -273,7 +270,7 @@ public class ConsulDiscoveryProperties { } public String getHealthCheckInterval() { - return healthCheckInterval; + return this.healthCheckInterval; } public void setHealthCheckInterval(String healthCheckInterval) { @@ -281,7 +278,7 @@ public class ConsulDiscoveryProperties { } public String getHealthCheckTimeout() { - return healthCheckTimeout; + return this.healthCheckTimeout; } public void setHealthCheckTimeout(String healthCheckTimeout) { @@ -289,7 +286,7 @@ public class ConsulDiscoveryProperties { } public String getHealthCheckCriticalTimeout() { - return healthCheckCriticalTimeout; + return this.healthCheckCriticalTimeout; } public void setHealthCheckCriticalTimeout(String healthCheckCriticalTimeout) { @@ -297,11 +294,16 @@ public class ConsulDiscoveryProperties { } public String getIpAddress() { - return ipAddress; + return this.ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + this.hostInfo.override = true; } public Integer getPort() { - return port; + return this.port; } public void setPort(Integer port) { @@ -309,7 +311,7 @@ public class ConsulDiscoveryProperties { } public Integer getManagementPort() { - return managementPort; + return this.managementPort; } public void setManagementPort(Integer managementPort) { @@ -317,7 +319,7 @@ public class ConsulDiscoveryProperties { } public Lifecycle getLifecycle() { - return lifecycle; + return this.lifecycle; } public void setLifecycle(Lifecycle lifecycle) { @@ -325,7 +327,7 @@ public class ConsulDiscoveryProperties { } public boolean isPreferIpAddress() { - return preferIpAddress; + return this.preferIpAddress; } public void setPreferIpAddress(boolean preferIpAddress) { @@ -333,7 +335,7 @@ public class ConsulDiscoveryProperties { } public boolean isPreferAgentAddress() { - return preferAgentAddress; + return this.preferAgentAddress; } public void setPreferAgentAddress(boolean preferAgentAddress) { @@ -341,7 +343,7 @@ public class ConsulDiscoveryProperties { } public int getCatalogServicesWatchDelay() { - return catalogServicesWatchDelay; + return this.catalogServicesWatchDelay; } public void setCatalogServicesWatchDelay(int catalogServicesWatchDelay) { @@ -349,7 +351,7 @@ public class ConsulDiscoveryProperties { } public int getCatalogServicesWatchTimeout() { - return catalogServicesWatchTimeout; + return this.catalogServicesWatchTimeout; } public void setCatalogServicesWatchTimeout(int catalogServicesWatchTimeout) { @@ -357,7 +359,7 @@ public class ConsulDiscoveryProperties { } public String getServiceName() { - return serviceName; + return this.serviceName; } public void setServiceName(String serviceName) { @@ -365,7 +367,7 @@ public class ConsulDiscoveryProperties { } public String getInstanceId() { - return instanceId; + return this.instanceId; } public void setInstanceId(String instanceId) { @@ -373,7 +375,7 @@ public class ConsulDiscoveryProperties { } public String getInstanceZone() { - return instanceZone; + return this.instanceZone; } public void setInstanceZone(String instanceZone) { @@ -381,7 +383,7 @@ public class ConsulDiscoveryProperties { } public String getInstanceGroup() { - return instanceGroup; + return this.instanceGroup; } public void setInstanceGroup(String instanceGroup) { @@ -389,7 +391,7 @@ public class ConsulDiscoveryProperties { } public String getDefaultZoneMetadataName() { - return defaultZoneMetadataName; + return this.defaultZoneMetadataName; } public void setDefaultZoneMetadataName(String defaultZoneMetadataName) { @@ -397,7 +399,7 @@ public class ConsulDiscoveryProperties { } public String getScheme() { - return scheme; + return this.scheme; } public void setScheme(String scheme) { @@ -405,7 +407,7 @@ public class ConsulDiscoveryProperties { } public String getManagementSuffix() { - return managementSuffix; + return this.managementSuffix; } public void setManagementSuffix(String managementSuffix) { @@ -413,7 +415,7 @@ public class ConsulDiscoveryProperties { } public Map getServerListQueryTags() { - return serverListQueryTags; + return this.serverListQueryTags; } public void setServerListQueryTags(Map serverListQueryTags) { @@ -421,7 +423,7 @@ public class ConsulDiscoveryProperties { } public Map getDatacenters() { - return datacenters; + return this.datacenters; } public void setDatacenters(Map datacenters) { @@ -429,7 +431,7 @@ public class ConsulDiscoveryProperties { } public String getDefaultQueryTag() { - return defaultQueryTag; + return this.defaultQueryTag; } public void setDefaultQueryTag(String defaultQueryTag) { @@ -437,7 +439,7 @@ public class ConsulDiscoveryProperties { } public boolean isQueryPassing() { - return queryPassing; + return this.queryPassing; } public void setQueryPassing(boolean queryPassing) { @@ -445,7 +447,7 @@ public class ConsulDiscoveryProperties { } public boolean isRegister() { - return register; + return this.register; } public void setRegister(boolean register) { @@ -453,7 +455,7 @@ public class ConsulDiscoveryProperties { } public boolean isDeregister() { - return deregister; + return this.deregister; } public void setDeregister(boolean deregister) { @@ -461,7 +463,7 @@ public class ConsulDiscoveryProperties { } public boolean isRegisterHealthCheck() { - return registerHealthCheck; + return this.registerHealthCheck; } public void setRegisterHealthCheck(boolean registerHealthCheck) { @@ -469,7 +471,7 @@ public class ConsulDiscoveryProperties { } public boolean isFailFast() { - return failFast; + return this.failFast; } public void setFailFast(boolean failFast) { @@ -477,7 +479,7 @@ public class ConsulDiscoveryProperties { } public Boolean getHealthCheckTlsSkipVerify() { - return healthCheckTlsSkipVerify; + return this.healthCheckTlsSkipVerify; } public void setHealthCheckTlsSkipVerify(Boolean healthCheckTlsSkipVerify) { @@ -485,7 +487,7 @@ public class ConsulDiscoveryProperties { } public int getOrder() { - return order; + return this.order; } public void setOrder(int order) { @@ -494,52 +496,50 @@ public class ConsulDiscoveryProperties { @Override public String toString() { - return new ToStringCreator(this) - .append("hostInfo", hostInfo) - .append("aclToken", aclToken) - .append("tags", tags) - .append("enabled", enabled) - .append("managementTags", managementTags) - .append("healthCheckPath", healthCheckPath) - .append("healthCheckUrl", healthCheckUrl) - .append("healthCheckHeaders", healthCheckHeaders) - .append("healthCheckInterval", healthCheckInterval) - .append("healthCheckTimeout", healthCheckTimeout) - .append("healthCheckCriticalTimeout", healthCheckCriticalTimeout) - .append("ipAddress", ipAddress) - .append("hostname", hostname) - .append("port", port) - .append("managementPort", managementPort) - .append("lifecycle", lifecycle) - .append("preferIpAddress", preferIpAddress) - .append("preferAgentAddress", preferAgentAddress) - .append("catalogServicesWatchDelay", catalogServicesWatchDelay) - .append("catalogServicesWatchTimeout", catalogServicesWatchTimeout) - .append("serviceName", serviceName) - .append("instanceId", instanceId) - .append("instanceZone", instanceZone) - .append("instanceGroup", instanceGroup) - .append("defaultZoneMetadataName", defaultZoneMetadataName) - .append("scheme", scheme) - .append("managementSuffix", managementSuffix) - .append("serverListQueryTags", serverListQueryTags) - .append("datacenters", datacenters) - .append("defaultQueryTag", defaultQueryTag) - .append("queryPassing", queryPassing) - .append("register", register) - .append("deregister", deregister) - .append("registerHealthCheck", registerHealthCheck) - .append("failFast", failFast) - .append("healthCheckTlsSkipVerify", healthCheckTlsSkipVerify) - .append("order", order) - .toString(); + return new ToStringCreator(this).append("hostInfo", this.hostInfo) + .append("aclToken", this.aclToken).append("tags", this.tags) + .append("enabled", this.enabled) + .append("managementTags", this.managementTags) + .append("healthCheckPath", this.healthCheckPath) + .append("healthCheckUrl", this.healthCheckUrl) + .append("healthCheckHeaders", this.healthCheckHeaders) + .append("healthCheckInterval", this.healthCheckInterval) + .append("healthCheckTimeout", this.healthCheckTimeout) + .append("healthCheckCriticalTimeout", this.healthCheckCriticalTimeout) + .append("ipAddress", this.ipAddress).append("hostname", this.hostname) + .append("port", this.port).append("managementPort", this.managementPort) + .append("lifecycle", this.lifecycle) + .append("preferIpAddress", this.preferIpAddress) + .append("preferAgentAddress", this.preferAgentAddress) + .append("catalogServicesWatchDelay", this.catalogServicesWatchDelay) + .append("catalogServicesWatchTimeout", this.catalogServicesWatchTimeout) + .append("serviceName", this.serviceName) + .append("instanceId", this.instanceId) + .append("instanceZone", this.instanceZone) + .append("instanceGroup", this.instanceGroup) + .append("defaultZoneMetadataName", this.defaultZoneMetadataName) + .append("scheme", this.scheme) + .append("managementSuffix", this.managementSuffix) + .append("serverListQueryTags", this.serverListQueryTags) + .append("datacenters", this.datacenters) + .append("defaultQueryTag", this.defaultQueryTag) + .append("queryPassing", this.queryPassing) + .append("register", this.register).append("deregister", this.deregister) + .append("registerHealthCheck", this.registerHealthCheck) + .append("failFast", this.failFast) + .append("healthCheckTlsSkipVerify", this.healthCheckTlsSkipVerify) + .append("order", this.order).toString(); } + /** + * Properties releated to the lifecycle. + */ public static class Lifecycle { + private boolean enabled = true; public boolean isEnabled() { - return enabled; + return this.enabled; } public void setEnabled(boolean enabled) { @@ -548,9 +548,9 @@ public class ConsulDiscoveryProperties { @Override public String toString() { - return "Lifecycle{" + - "enabled=" + enabled + - '}'; + return "Lifecycle{" + "enabled=" + this.enabled + '}'; } + } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulPing.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulPing.java index 0e660f69..9440404e 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulPing.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulPing.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +20,13 @@ import com.netflix.loadbalancer.IPing; import com.netflix.loadbalancer.Server; /** - * "Ping" Consul - * i.e. we dont do a real "ping". We just assume that the server is up if Consul says so + * "Ping" Consul i.e. we dont do a real "ping". We just assume that the server is up if + * Consul says so + * * @author Spencer Gibb */ public class ConsulPing implements IPing { + @Override public boolean isAlive(Server server) { boolean isAlive = true; @@ -36,4 +38,5 @@ public class ConsulPing implements IPing { return isAlive; } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulRibbonClientConfiguration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulRibbonClientConfiguration.java index 52f3ae21..94130934 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulRibbonClientConfiguration.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulRibbonClientConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,16 +47,17 @@ import static com.netflix.client.config.CommonClientConfigKey.EnableZoneAffinity */ @Configuration public class ConsulRibbonClientConfiguration { + + protected static final String VALUE_NOT_SET = "__not__set__"; + + protected static final String DEFAULT_NAMESPACE = "ribbon"; + @Autowired private ConsulClient client; @Value("${ribbon.client.name}") private String serviceId = "client"; - protected static final String VALUE_NOT_SET = "__not__set__"; - - protected static final String DEFAULT_NAMESPACE = "ribbon"; - public ConsulRibbonClientConfiguration() { } @@ -66,8 +67,9 @@ public class ConsulRibbonClientConfiguration { @Bean @ConditionalOnMissingBean - public ServerList ribbonServerList(IClientConfig config, ConsulDiscoveryProperties properties) { - ConsulServerList serverList = new ConsulServerList(client, properties); + public ServerList ribbonServerList(IClientConfig config, + ConsulDiscoveryProperties properties) { + ConsulServerList serverList = new ConsulServerList(this.client, properties); serverList.initWithNiwsConfig(config); return serverList; } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServer.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServer.java index 8c4ded7f..3283c3e7 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServer.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,17 +30,19 @@ import static org.springframework.cloud.consul.discovery.ConsulServerUtils.findH public class ConsulServer extends Server { private final MetaInfo metaInfo; + private final HealthService service; + private final Map metadata; public ConsulServer(final HealthService healthService) { super(findHost(healthService), healthService.getService().getPort()); this.service = healthService; this.metadata = ConsulServerUtils.getMetadata(this.service); - metaInfo = new MetaInfo() { + this.metaInfo = new MetaInfo() { @Override public String getAppName() { - return service.getService().getService(); + return ConsulServer.this.service.getService().getService(); } @Override @@ -55,7 +57,7 @@ public class ConsulServer extends Server { @Override public String getInstanceId() { - return service.getService().getId(); + return ConsulServer.this.service.getService().getId(); } }; @@ -64,7 +66,7 @@ public class ConsulServer extends Server { @Override public MetaInfo getMetaInfo() { - return metaInfo; + return this.metaInfo; } public HealthService getHealthService() { @@ -72,7 +74,7 @@ public class ConsulServer extends Server { } public Map getMetadata() { - return metadata; + return this.metadata; } public boolean isPassingChecks() { @@ -83,4 +85,5 @@ public class ConsulServer extends Server { } return true; } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerIntrospector.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerIntrospector.java index f607ece1..bd53d1ad 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerIntrospector.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerIntrospector.java @@ -1,10 +1,30 @@ -package org.springframework.cloud.consul.discovery; +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import com.netflix.loadbalancer.Server; -import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector; +package org.springframework.cloud.consul.discovery; import java.util.Map; +import com.netflix.loadbalancer.Server; + +import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector; + +/** + * @author Spencer Gibb + */ public class ConsulServerIntrospector extends DefaultServerIntrospector { @Override @@ -24,4 +44,5 @@ public class ConsulServerIntrospector extends DefaultServerIntrospector { } return super.getMetadata(server); } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerList.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerList.java index 21653bf7..90693323 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerList.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerList.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import com.netflix.loadbalancer.AbstractServerList; public class ConsulServerList extends AbstractServerList { private final ConsulClient client; + private final ConsulDiscoveryProperties properties; private String serviceId; @@ -44,15 +45,15 @@ public class ConsulServerList extends AbstractServerList { } protected ConsulClient getClient() { - return client; + return this.client; } protected ConsulDiscoveryProperties getProperties() { - return properties; + return this.properties; } protected String getServiceId() { - return serviceId; + return this.serviceId; } @Override @@ -86,8 +87,8 @@ public class ConsulServerList extends AbstractServerList { /** * Transforms the response from Consul in to a list of usable {@link ConsulServer}s. - * - * @param healthServices the initial list of servers from Consul. Guaranteed to be non-empty list + * @param healthServices the initial list of servers from Consul. Guaranteed to be + * non-empty list * @return ConsulServer instances * @see ConsulServer#ConsulServer(HealthService) */ @@ -95,8 +96,10 @@ public class ConsulServerList extends AbstractServerList { List servers = new ArrayList<>(); for (HealthService service : healthServices) { ConsulServer server = new ConsulServer(service); - if (server.getMetadata().containsKey(this.properties.getDefaultZoneMetadataName())) { - server.setZone(server.getMetadata().get(this.properties.getDefaultZoneMetadataName())); + if (server.getMetadata() + .containsKey(this.properties.getDefaultZoneMetadataName())) { + server.setZone(server.getMetadata() + .get(this.properties.getDefaultZoneMetadataName())); } servers.add(server); } @@ -104,9 +107,9 @@ public class ConsulServerList extends AbstractServerList { } /** - * This method will create the {@link QueryParams} to use when retrieving the - * services from Consul. By default {@link QueryParams#DEFAULT} is used. In case - * a datacenter is specified for the current serviceId {@link QueryParams#datacenter} is set. + * This method will create the {@link QueryParams} to use when retrieving the services + * from Consul. By default {@link QueryParams#DEFAULT} is used. In case a datacenter + * is specified for the current serviceId {@link QueryParams#datacenter} is set. * @return an instance of {@link QueryParams} */ protected QueryParams createQueryParamsForClientRequest() { @@ -128,9 +131,10 @@ public class ConsulServerList extends AbstractServerList { @Override public String toString() { final StringBuilder sb = new StringBuilder("ConsulServerList{"); - sb.append("serviceId='").append(serviceId).append('\''); + sb.append("serviceId='").append(this.serviceId).append('\''); sb.append(", tag=").append(getTag()); sb.append('}'); return sb.toString(); } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerUtils.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerUtils.java index 0a453237..92ab5dca 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerUtils.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServerUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,17 +34,22 @@ import org.springframework.util.StringUtils; * @author Spencer Gibb * @author Semenkov Alexey */ -public class ConsulServerUtils { +public final class ConsulServerUtils { private static final Log log = LogFactory.getLog(ConsulServerUtils.class); + private ConsulServerUtils() { + throw new IllegalStateException("Can't instantiate a utility class"); + } + public static String findHost(HealthService healthService) { HealthService.Service service = healthService.getService(); HealthService.Node node = healthService.getNode(); if (StringUtils.hasText(service.getAddress())) { return fixIPv6Address(service.getAddress()); - } else if (StringUtils.hasText(node.getAddress())) { + } + else if (StringUtils.hasText(node.getAddress())) { return fixIPv6Address(node.getAddress()); } return node.getNode(); @@ -57,13 +62,13 @@ public class ConsulServerUtils { return "[" + inetAdr.getHostName() + "]"; } return address; - } catch (UnknownHostException e) { + } + catch (UnknownHostException e) { log.debug("Not InetAddress: " + address + " , resolved as is."); return address; } } - public static Map getMetadata(HealthService healthService) { return getMetadata(healthService.getService().getTags()); } @@ -74,18 +79,18 @@ public class ConsulServerUtils { for (String tag : tags) { String[] parts = StringUtils.delimitedListToStringArray(tag, "="); switch (parts.length) { - case 0: - break; - case 1: - metadata.put(parts[0], parts[0]); - break; - case 2: - metadata.put(parts[0], parts[1]); - break; - default: - String[] end = Arrays.copyOfRange(parts, 1, parts.length); - metadata.put(parts[0], StringUtils.arrayToDelimitedString(end, "=")); - break; + case 0: + break; + case 1: + metadata.put(parts[0], parts[0]); + break; + case 2: + metadata.put(parts[0], parts[1]); + break; + default: + String[] end = Arrays.copyOfRange(parts, 1, parts.length); + metadata.put(parts[0], StringUtils.arrayToDelimitedString(end, "=")); + break; } } @@ -93,4 +98,5 @@ public class ConsulServerUtils { return metadata; } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/HealthServiceServerListFilter.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/HealthServiceServerListFilter.java index f04a0af8..8e841ecb 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/HealthServiceServerListFilter.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/HealthServiceServerListFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,10 +25,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * ServerList implementation that filters ConsulServers based on if all their Health Checks are PASSING. + * ServerList implementation that filters ConsulServers based on if all their Health + * Checks are PASSING. + * * @author Spencer Gibb */ public class HealthServiceServerListFilter implements ServerListFilter { + private static final Log log = LogFactory.getLog(HealthServiceServerListFilter.class); @Override @@ -43,9 +46,11 @@ public class HealthServiceServerListFilter implements ServerListFilter { filtered.add(server); } - } else { - if (log.isDebugEnabled()) { - log.debug("Unable to determine aliveness of server type " + server.getClass() + ", " + server); + } + else { + if (log.isDebugEnabled()) { + log.debug("Unable to determine aliveness of server type " + + server.getClass() + ", " + server); } filtered.add(server); } @@ -53,4 +58,5 @@ public class HealthServiceServerListFilter implements ServerListFilter { return filtered; } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/HeartbeatProperties.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/HeartbeatProperties.java index 1ddb4863..feb1bacc 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/HeartbeatProperties.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/HeartbeatProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,11 +28,18 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.style.ToStringCreator; import org.springframework.validation.annotation.Validated; +/** + * Properties related to hearbeat verification. + * + * @author Spencer Gibb + */ @ConfigurationProperties(prefix = "spring.cloud.consul.discovery.heartbeat") @Validated public class HeartbeatProperties { - private static final Log log = org.apache.commons.logging.LogFactory.getLog(HeartbeatProperties.class); + private static final Log log = org.apache.commons.logging.LogFactory + .getLog(HeartbeatProperties.class); + // TODO: change enabled to default to true when I stop seeing messages like // [WARN] agent: Check 'service:testConsulApp:xtest:8080' missed TTL, is now critical boolean enabled = false; @@ -47,63 +54,62 @@ public class HeartbeatProperties { @DecimalMax("0.9") private double intervalRatio = 2.0 / 3.0; - //TODO: did heartbeatInterval need to be a field? + // TODO: did heartbeatInterval need to be a field? - protected Period computeHearbeatInterval() { - // heartbeat rate at ratio * ttl, but no later than ttl -1s and, (under lesser - // priority), no sooner than 1s from now - double interval = ttlValue * intervalRatio; - double max = Math.max(interval, 1); - int ttlMinus1 = ttlValue - 1; - double min = Math.min(ttlMinus1, max); + protected Period computeHearbeatInterval() { + // heartbeat rate at ratio * ttl, but no later than ttl -1s and, (under lesser + // priority), no sooner than 1s from now + double interval = this.ttlValue * this.intervalRatio; + double max = Math.max(interval, 1); + int ttlMinus1 = this.ttlValue - 1; + double min = Math.min(ttlMinus1, max); Period heartbeatInterval = new Period(Math.round(1000 * min)); log.debug("Computed heartbeatInterval: " + heartbeatInterval); return heartbeatInterval; - } + } - public String getTtl() { - return ttlValue + ttlUnit; + public String getTtl() { + return this.ttlValue + this.ttlUnit; } public boolean isEnabled() { return this.enabled; } - public @Min(1) int getTtlValue() { - return this.ttlValue; - } - - public @NotNull String getTtlUnit() { - return this.ttlUnit; - } - - public @DecimalMin("0.1") @DecimalMax("0.9") double getIntervalRatio() { - return this.intervalRatio; - } - public void setEnabled(boolean enabled) { this.enabled = enabled; } + public @Min(1) int getTtlValue() { + return this.ttlValue; + } + public void setTtlValue(@Min(1) int ttlValue) { this.ttlValue = ttlValue; } + public @NotNull String getTtlUnit() { + return this.ttlUnit; + } + public void setTtlUnit(@NotNull String ttlUnit) { this.ttlUnit = ttlUnit; } - public void setIntervalRatio(@DecimalMin("0.1") @DecimalMax("0.9") double intervalRatio) { + public @DecimalMin("0.1") @DecimalMax("0.9") double getIntervalRatio() { + return this.intervalRatio; + } + + public void setIntervalRatio( + @DecimalMin("0.1") @DecimalMax("0.9") double intervalRatio) { this.intervalRatio = intervalRatio; } @Override public String toString() { - return new ToStringCreator(this) - .append("enabled", enabled) - .append("ttlValue", ttlValue) - .append("ttlUnit", ttlUnit) - .append("intervalRatio", intervalRatio) - .toString(); + return new ToStringCreator(this).append("enabled", this.enabled) + .append("ttlValue", this.ttlValue).append("ttlUnit", this.ttlUnit) + .append("intervalRatio", this.intervalRatio).toString(); } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/RibbonConsulAutoConfiguration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/RibbonConsulAutoConfiguration.java index d43512d4..dc62a427 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/RibbonConsulAutoConfiguration.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/RibbonConsulAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/TestConsulLifecycleConfiguration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/TestConsulLifecycleConfiguration.java deleted file mode 100644 index e69de29b..00000000 diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/TtlScheduler.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/TtlScheduler.java index 67a8e482..3c373aee 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/TtlScheduler.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/TtlScheduler.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,9 +31,11 @@ import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; /** * Created by nicu on 11.03.2015. + * * @author Stéphane LEROY */ public class TtlScheduler { + private static final Log log = LogFactory.getLog(ConsulDiscoveryClient.class); private final Map serviceHeartbeats = new ConcurrentHashMap<>(); @@ -57,41 +59,45 @@ public class TtlScheduler { /** * Add a service to the checks loop. + * @param instanceId instance id */ public void add(String instanceId) { - ScheduledFuture task = scheduler.scheduleAtFixedRate(new ConsulHeartbeatTask( - instanceId), configuration.computeHearbeatInterval() - .toStandardDuration().getMillis()); - ScheduledFuture previousTask = serviceHeartbeats.put(instanceId, task); + ScheduledFuture task = this.scheduler.scheduleAtFixedRate( + new ConsulHeartbeatTask(instanceId), this.configuration + .computeHearbeatInterval().toStandardDuration().getMillis()); + ScheduledFuture previousTask = this.serviceHeartbeats.put(instanceId, task); if (previousTask != null) { previousTask.cancel(true); } } public void remove(String instanceId) { - ScheduledFuture task = serviceHeartbeats.get(instanceId); + ScheduledFuture task = this.serviceHeartbeats.get(instanceId); if (task != null) { task.cancel(true); } - serviceHeartbeats.remove(instanceId); + this.serviceHeartbeats.remove(instanceId); } private class ConsulHeartbeatTask implements Runnable { + private String checkId; ConsulHeartbeatTask(String serviceId) { this.checkId = serviceId; - if (!checkId.startsWith("service:")) { - checkId = "service:" + checkId; + if (!this.checkId.startsWith("service:")) { + this.checkId = "service:" + this.checkId; } } @Override public void run() { - client.agentCheckPass(checkId); + TtlScheduler.this.client.agentCheckPass(this.checkId); if (log.isDebugEnabled()) { - log.debug("Sending consul heartbeat for: " + checkId); + log.debug("Sending consul heartbeat for: " + this.checkId); } } + } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/configclient/ConsulConfigServerAutoConfiguration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/configclient/ConsulConfigServerAutoConfiguration.java index 833c3d38..9e515d03 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/configclient/ConsulConfigServerAutoConfiguration.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/configclient/ConsulConfigServerAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ package org.springframework.cloud.consul.discovery.configclient; import javax.annotation.PostConstruct; +import com.ecwid.consul.v1.ConsulClient; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -26,8 +28,6 @@ import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; -import com.ecwid.consul.v1.ConsulClient; - /** * Extra configuration for config server if it happens to be registered with Consul. * @@ -52,7 +52,7 @@ public class ConsulConfigServerAutoConfiguration { } String prefix = this.server.getPrefix(); if (StringUtils.hasText(prefix)) { - this.properties.getTags().add("configPath="+prefix); + this.properties.getTags().add("configPath=" + prefix); } } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/configclient/ConsulDiscoveryClientConfigServiceBootstrapConfiguration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/configclient/ConsulDiscoveryClientConfigServiceBootstrapConfiguration.java index 9dff098c..0535cf99 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/configclient/ConsulDiscoveryClientConfigServiceBootstrapConfiguration.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/configclient/ConsulDiscoveryClientConfigServiceBootstrapConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,8 @@ import org.springframework.context.annotation.Configuration; @ConditionalOnClass(ConfigServicePropertySourceLocator.class) @ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = false) @Configuration -@ImportAutoConfiguration({ ConsulAutoConfiguration.class, ConsulDiscoveryClientConfiguration.class}) +@ImportAutoConfiguration({ ConsulAutoConfiguration.class, + ConsulDiscoveryClientConfiguration.class }) public class ConsulDiscoveryClientConfigServiceBootstrapConfiguration { } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/AliveServerListFilter.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/AliveServerListFilter.java index c98267e8..ee49dd9a 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/AliveServerListFilter.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/AliveServerListFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,21 +20,23 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; -import org.springframework.cloud.consul.discovery.ConsulServer; - import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerListFilter; +import org.springframework.cloud.consul.discovery.ConsulServer; + /** * Server filter: returns only alive servers. Each consul agent runs a serf agent which is * a member of the serf gossip pool. The serf status (alive/failed/etc) is reflected in 2 * consul APIs: in the agent API and in the catalog API. We prefer the agent API because * it is most up to date (or perhaps we should intersect them and pick members that are * live in both). + * * @author nicu marasoiu on 10.03.2015. */ @Deprecated public class AliveServerListFilter implements ServerListFilter { + private FilteringAgentClient filteringAgentClient; public AliveServerListFilter(FilteringAgentClient filteringAgentClient) { @@ -43,14 +45,16 @@ public class AliveServerListFilter implements ServerListFilter { @Override public List getFilteredListOfServers(List servers) { - Set liveNodes = filteringAgentClient.getAliveAgentsAddresses(); + Set liveNodes = this.filteringAgentClient.getAliveAgentsAddresses(); List filteredServers = new ArrayList<>(); for (Server server : servers) { ConsulServer consulServer = ConsulServer.class.cast(server); - if (liveNodes.contains(consulServer.getHealthService().getService().getAddress())) { + if (liveNodes.contains( + consulServer.getHealthService().getService().getAddress())) { filteredServers.add(server); } } return filteredServers; } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/FilteringAgentClient.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/FilteringAgentClient.java index 37ea304c..825f16ec 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/FilteringAgentClient.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/FilteringAgentClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,11 +21,14 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import org.springframework.cloud.consul.model.SerfStatusEnum; - import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.agent.model.Member; +import org.springframework.cloud.consul.model.SerfStatusEnum; + +/** + * @author Nicu Marasoiu + */ @Deprecated public class FilteringAgentClient { @@ -38,7 +41,7 @@ public class FilteringAgentClient { } public List getAliveAgents() { - List members = client.getAgentMembers().getValue(); + List members = this.client.getAgentMembers().getValue(); List liveMembers = new ArrayList<>(members.size()); for (Member peer : members) { if (peer.getStatus() == ALIVE_STATUS) { @@ -55,4 +58,5 @@ public class FilteringAgentClient { } return addresses; } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/ServiceCheckServerListFilter.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/ServiceCheckServerListFilter.java index 7449cc97..cbca3c79 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/ServiceCheckServerListFilter.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/filters/ServiceCheckServerListFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,8 @@ import com.netflix.loadbalancer.ServerListFilter; /** * Created by nicu on 12.03.2015. + * + * @author Nicu Marasoiu */ @Deprecated public class ServiceCheckServerListFilter implements ServerListFilter { @@ -44,9 +46,9 @@ public class ServiceCheckServerListFilter implements ServerListFilter { for (Server server : servers) { String appName = server.getMetaInfo().getAppName(); String instanceId = server.getMetaInfo().getInstanceId(); - //TODO: cache getHealthChecks? this is hit often - List serviceChecks = client.getHealthChecksForService(appName, - QueryParams.DEFAULT).getValue(); + // TODO: cache getHealthChecks? this is hit often + List serviceChecks = this.client + .getHealthChecksForService(appName, QueryParams.DEFAULT).getValue(); boolean serviceOk = true; for (Check check : serviceChecks) { if (check.getServiceId().equals(instanceId) diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistration.java index 4d5bcb95..e2ae41d2 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistration.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistration.java @@ -20,6 +20,8 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import com.ecwid.consul.v1.agent.model.NewService; + import org.springframework.cloud.client.discovery.ManagementServerPortUtils; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; @@ -31,29 +33,38 @@ import org.springframework.core.env.Environment; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import com.ecwid.consul.v1.agent.model.NewService; - /** * @author Spencer Gibb */ public class ConsulAutoRegistration extends ConsulRegistration { + /** + * Instance ID separator. + */ public static final char SEPARATOR = '-'; private final AutoServiceRegistrationProperties autoServiceRegistrationProperties; + private final ApplicationContext context; + private final HeartbeatProperties heartbeatProperties; + private final List managementRegistrationCustomizers; @Deprecated - public ConsulAutoRegistration(NewService service, AutoServiceRegistrationProperties autoServiceRegistrationProperties, - ConsulDiscoveryProperties properties, ApplicationContext context, HeartbeatProperties heartbeatProperties) { - this(service, autoServiceRegistrationProperties, properties, context, heartbeatProperties, Collections.emptyList()); + public ConsulAutoRegistration(NewService service, + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ConsulDiscoveryProperties properties, ApplicationContext context, + HeartbeatProperties heartbeatProperties) { + this(service, autoServiceRegistrationProperties, properties, context, + heartbeatProperties, Collections.emptyList()); } - public ConsulAutoRegistration(NewService service, AutoServiceRegistrationProperties autoServiceRegistrationProperties, - ConsulDiscoveryProperties properties, ApplicationContext context, HeartbeatProperties heartbeatProperties, - List managementRegistrationCustomizers) { + public ConsulAutoRegistration(NewService service, + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ConsulDiscoveryProperties properties, ApplicationContext context, + HeartbeatProperties heartbeatProperties, + List managementRegistrationCustomizers) { super(service, properties); this.autoServiceRegistrationProperties = autoServiceRegistrationProperties; this.context = context; @@ -61,24 +72,8 @@ public class ConsulAutoRegistration extends ConsulRegistration { this.managementRegistrationCustomizers = managementRegistrationCustomizers; } - public void initializePort(int knownPort) { - if (getService().getPort() == null) { - // not set by properties - getService().setPort(knownPort); - } - // we might not have a port until now, so this is the earliest we - // can create a check - - setCheck(getService(), this.autoServiceRegistrationProperties, getProperties(), - this.context, this.heartbeatProperties); - } - - public ConsulAutoRegistration managementRegistration() { - return managementRegistration(this.autoServiceRegistrationProperties, getProperties(), - this.context, this.managementRegistrationCustomizers, this.heartbeatProperties); - } - - public static ConsulAutoRegistration registration(AutoServiceRegistrationProperties autoServiceRegistrationProperties, + public static ConsulAutoRegistration registration( + AutoServiceRegistrationProperties autoServiceRegistrationProperties, ConsulDiscoveryProperties properties, ApplicationContext context, List registrationCustomizers, List managementRegistrationCustomizers, @@ -87,7 +82,7 @@ public class ConsulAutoRegistration extends ConsulRegistration { NewService service = new NewService(); String appName = getAppName(properties, context.getEnvironment()); service.setId(getInstanceId(properties, context)); - if(!properties.isPreferAgentAddress()) { + if (!properties.isPreferAgentAddress()) { service.setAddress(properties.getHostname()); } service.setName(normalizeForDns(appName)); @@ -96,16 +91,20 @@ public class ConsulAutoRegistration extends ConsulRegistration { if (properties.getPort() != null) { service.setPort(properties.getPort()); // we know the port and can set the check - setCheck(service, autoServiceRegistrationProperties, properties, context, heartbeatProperties); + setCheck(service, autoServiceRegistrationProperties, properties, context, + heartbeatProperties); } - ConsulAutoRegistration registration = new ConsulAutoRegistration(service, autoServiceRegistrationProperties, - properties, context, heartbeatProperties, managementRegistrationCustomizers); + ConsulAutoRegistration registration = new ConsulAutoRegistration(service, + autoServiceRegistrationProperties, properties, context, + heartbeatProperties, managementRegistrationCustomizers); customize(registrationCustomizers, registration); return registration; } - public static void customize(List registrationCustomizers, ConsulAutoRegistration registration) { + public static void customize( + List registrationCustomizers, + ConsulAutoRegistration registration) { if (registrationCustomizers != null) { for (ConsulRegistrationCustomizer customizer : registrationCustomizers) { customizer.customize(registration); @@ -119,9 +118,11 @@ public class ConsulAutoRegistration extends ConsulRegistration { HeartbeatProperties heartbeatProperties) { if (properties.isRegisterHealthCheck() && service.getCheck() == null) { Integer checkPort; - if (shouldRegisterManagement(autoServiceRegistrationProperties, properties, context)) { + if (shouldRegisterManagement(autoServiceRegistrationProperties, properties, + context)) { checkPort = getManagementPort(properties, context); - } else { + } + else { checkPort = service.getPort(); } Assert.notNull(checkPort, "checkPort may not be null"); @@ -137,18 +138,24 @@ public class ConsulAutoRegistration extends ConsulRegistration { NewService management = new NewService(); management.setId(getManagementServiceId(properties, context)); management.setAddress(properties.getHostname()); - management.setName(getManagementServiceName(properties, context.getEnvironment())); + management + .setName(getManagementServiceName(properties, context.getEnvironment())); management.setPort(getManagementPort(properties, context)); management.setTags(properties.getManagementTags()); if (properties.isRegisterHealthCheck()) { - management.setCheck(createCheck(getManagementPort(properties, context), heartbeatProperties, properties)); + management.setCheck(createCheck(getManagementPort(properties, context), + heartbeatProperties, properties)); } - ConsulAutoRegistration registration = new ConsulAutoRegistration(management, autoServiceRegistrationProperties, properties, context, heartbeatProperties, managementRegistrationCustomizers); + ConsulAutoRegistration registration = new ConsulAutoRegistration(management, + autoServiceRegistrationProperties, properties, context, + heartbeatProperties, managementRegistrationCustomizers); managementCustomize(managementRegistrationCustomizers, registration); return registration; } - public static void managementCustomize(List registrationCustomizers, ConsulAutoRegistration registration) { + public static void managementCustomize( + List registrationCustomizers, + ConsulAutoRegistration registration) { if (registrationCustomizers != null) { for (ConsulManagementRegistrationCustomizer customizer : registrationCustomizers) { customizer.customize(registration); @@ -156,17 +163,23 @@ public class ConsulAutoRegistration extends ConsulRegistration { } } - public static String getInstanceId(ConsulDiscoveryProperties properties, ApplicationContext context) { + public static String getInstanceId(ConsulDiscoveryProperties properties, + ApplicationContext context) { if (!StringUtils.hasText(properties.getInstanceId())) { - return normalizeForDns(IdUtils.getDefaultInstanceId(context.getEnvironment(), false)); + return normalizeForDns( + IdUtils.getDefaultInstanceId(context.getEnvironment(), false)); } return normalizeForDns(properties.getInstanceId()); } public static String normalizeForDns(String s) { if (s == null || !Character.isLetter(s.charAt(0)) - || !Character.isLetterOrDigit(s.charAt(s.length()-1))) { - throw new IllegalArgumentException("Consul service ids must not be empty, must start with a letter, end with a letter or digit, and have as interior characters only letters, digits, and hyphen: "+s); + || !Character.isLetterOrDigit(s.charAt(s.length() - 1))) { + throw new IllegalArgumentException( + "Consul service ids must not be empty, must start " + + "with a letter, end with a letter or digit, " + + "and have as interior characters only letters, " + + "digits, and hyphen: " + s); } StringBuilder normalized = new StringBuilder(); @@ -175,7 +188,8 @@ public class ConsulAutoRegistration extends ConsulRegistration { Character toAppend = null; if (Character.isLetterOrDigit(curr)) { toAppend = curr; - } else if (prev == null || !(prev == SEPARATOR)) { + } + else if (prev == null || !(prev == SEPARATOR)) { toAppend = SEPARATOR; } if (toAppend != null) { @@ -191,20 +205,23 @@ public class ConsulAutoRegistration extends ConsulRegistration { List tags = new LinkedList<>(properties.getTags()); if (!StringUtils.isEmpty(properties.getInstanceZone())) { - tags.add(properties.getDefaultZoneMetadataName() + "=" + properties.getInstanceZone()); + tags.add(properties.getDefaultZoneMetadataName() + "=" + + properties.getInstanceZone()); } if (!StringUtils.isEmpty(properties.getInstanceGroup())) { tags.add("group=" + properties.getInstanceGroup()); } - //store the secure flag in the tags so that clients will be able to figure out whether to use http or https automatically - tags.add("secure=" + Boolean.toString(properties.getScheme().equalsIgnoreCase("https"))); + // store the secure flag in the tags so that clients will be able to figure out + // whether to use http or https automatically + tags.add("secure=" + + Boolean.toString(properties.getScheme().equalsIgnoreCase("https"))); return tags; } - public static NewService.Check createCheck(Integer port, HeartbeatProperties ttlConfig, - ConsulDiscoveryProperties properties) { + public static NewService.Check createCheck(Integer port, + HeartbeatProperties ttlConfig, ConsulDiscoveryProperties properties) { NewService.Check check = new NewService.Check(); if (ttlConfig.isEnabled()) { check.setTtl(ttlConfig.getTtl()); @@ -216,25 +233,29 @@ public class ConsulAutoRegistration extends ConsulRegistration { if (properties.getHealthCheckUrl() != null) { check.setHttp(properties.getHealthCheckUrl()); - } else { + } + else { check.setHttp(String.format("%s://%s:%s%s", properties.getScheme(), - properties.getHostname(), port, - properties.getHealthCheckPath())); + properties.getHostname(), port, properties.getHealthCheckPath())); } check.setHeader(properties.getHealthCheckHeaders()); check.setInterval(properties.getHealthCheckInterval()); check.setTimeout(properties.getHealthCheckTimeout()); if (StringUtils.hasText(properties.getHealthCheckCriticalTimeout())) { - check.setDeregisterCriticalServiceAfter(properties.getHealthCheckCriticalTimeout()); + check.setDeregisterCriticalServiceAfter( + properties.getHealthCheckCriticalTimeout()); } check.setTlsSkipVerify(properties.getHealthCheckTlsSkipVerify()); return check; } /** + * @param properties consul discovery properties + * @param env Spring environment * @return the app name, currently the spring.application.name property */ - public static String getAppName(ConsulDiscoveryProperties properties, Environment env) { + public static String getAppName(ConsulDiscoveryProperties properties, + Environment env) { final String appName = properties.getServiceName(); if (StringUtils.hasText(appName)) { return appName; @@ -243,44 +264,83 @@ public class ConsulAutoRegistration extends ConsulRegistration { } /** - * @return if the management service should be registered with the {@link ServiceRegistry} + * @param autoServiceRegistrationProperties registration properties + * @param properties discovery properties + * @param context Spring application context + * @return if the management service should be registered with the + * {@link ServiceRegistry} */ - public static boolean shouldRegisterManagement(AutoServiceRegistrationProperties autoServiceRegistrationProperties, ConsulDiscoveryProperties properties, ApplicationContext context) { + public static boolean shouldRegisterManagement( + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ConsulDiscoveryProperties properties, ApplicationContext context) { return autoServiceRegistrationProperties.isRegisterManagement() && getManagementPort(properties, context) != null && ManagementServerPortUtils.isDifferent(context); } /** + * @param properties discovery properties + * @param context Spring application context * @return the serviceId of the Management Service */ - public static String getManagementServiceId(ConsulDiscoveryProperties properties, ApplicationContext context) { + public static String getManagementServiceId(ConsulDiscoveryProperties properties, + ApplicationContext context) { final String instanceId = properties.getInstanceId(); if (StringUtils.hasText(instanceId)) { - return normalizeForDns(instanceId + SEPARATOR + properties.getManagementSuffix()); + return normalizeForDns( + instanceId + SEPARATOR + properties.getManagementSuffix()); } - return normalizeForDns(IdUtils.getDefaultInstanceId(context.getEnvironment(), false)) + SEPARATOR + properties.getManagementSuffix(); + return normalizeForDns( + IdUtils.getDefaultInstanceId(context.getEnvironment(), false)) + SEPARATOR + + properties.getManagementSuffix(); } /** + * @param properties discovery properties + * @param env Spring environment * @return the service name of the Management Service */ - public static String getManagementServiceName(ConsulDiscoveryProperties properties, Environment env) { + public static String getManagementServiceName(ConsulDiscoveryProperties properties, + Environment env) { final String appName = properties.getServiceName(); if (StringUtils.hasText(appName)) { - return normalizeForDns(appName + SEPARATOR + properties.getManagementSuffix()); + return normalizeForDns( + appName + SEPARATOR + properties.getManagementSuffix()); } - return normalizeForDns(getAppName(properties, env)) + SEPARATOR + properties.getManagementSuffix(); + return normalizeForDns(getAppName(properties, env)) + SEPARATOR + + properties.getManagementSuffix(); } /** + * @param properties discovery properties + * @param context Spring application context * @return the port of the Management Service */ - public static Integer getManagementPort(ConsulDiscoveryProperties properties, ApplicationContext context) { + public static Integer getManagementPort(ConsulDiscoveryProperties properties, + ApplicationContext context) { // If an alternate external port is specified, use it instead if (properties.getManagementPort() != null) { return properties.getManagementPort(); } return ManagementServerPortUtils.getPort(context); } + + public void initializePort(int knownPort) { + if (getService().getPort() == null) { + // not set by properties + getService().setPort(knownPort); + } + // we might not have a port until now, so this is the earliest we + // can create a check + + setCheck(getService(), this.autoServiceRegistrationProperties, getProperties(), + this.context, this.heartbeatProperties); + } + + public ConsulAutoRegistration managementRegistration() { + return managementRegistration(this.autoServiceRegistrationProperties, + getProperties(), this.context, this.managementRegistrationCustomizers, + this.heartbeatProperties); + } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistration.java index 5d31aa2f..1ad76254 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistration.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.cloud.consul.serviceregistry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; @@ -29,11 +30,13 @@ import org.springframework.util.StringUtils; /** * @author Spencer Gibb */ -public class ConsulAutoServiceRegistration extends AbstractAutoServiceRegistration { +public class ConsulAutoServiceRegistration + extends AbstractAutoServiceRegistration { private static Log log = LogFactory.getLog(ConsulAutoServiceRegistration.class); private ConsulDiscoveryProperties properties; + private ConsulAutoRegistration registration; public ConsulAutoServiceRegistration(ConsulServiceRegistry serviceRegistry, @@ -50,10 +53,12 @@ public class ConsulAutoServiceRegistration extends AbstractAutoServiceRegistrati @Override protected ConsulAutoRegistration getRegistration() { - if (this.registration.getService().getPort() == null && this.getPort().get() > 0) { + if (this.registration.getService().getPort() == null + && this.getPort().get() > 0) { this.registration.initializePort(this.getPort().get()); } - Assert.notNull(this.registration.getService().getPort(), "service.port has not been set"); + Assert.notNull(this.registration.getService().getPort(), + "service.port has not been set"); return this.registration; } @@ -89,7 +94,7 @@ public class ConsulAutoServiceRegistration extends AbstractAutoServiceRegistrati @Override protected Object getConfiguration() { - return properties; + return this.properties; } @Override @@ -116,7 +121,7 @@ public class ConsulAutoServiceRegistration extends AbstractAutoServiceRegistrati @Override @SuppressWarnings("deprecation") protected String getAppName() { - String appName = properties.getServiceName(); + String appName = this.properties.getServiceName(); return StringUtils.isEmpty(appName) ? super.getAppName() : appName; } @@ -125,4 +130,5 @@ public class ConsulAutoServiceRegistration extends AbstractAutoServiceRegistrati // do nothing so we can listen for this event in a different class // this ensures start() can be retried if spring-retry is available } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationAutoConfiguration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationAutoConfiguration.java index 56bac0d9..931a3623 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationAutoConfiguration.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationAutoConfiguration.java @@ -44,7 +44,8 @@ import org.springframework.context.annotation.Configuration; @ConditionalOnMissingBean(type = "org.springframework.cloud.consul.discovery.ConsulLifecycle") @ConditionalOnConsulEnabled @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) -@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, ConsulServiceRegistryAutoConfiguration.class}) +@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class, + ConsulServiceRegistryAutoConfiguration.class }) public class ConsulAutoServiceRegistrationAutoConfiguration { @Autowired @@ -62,31 +63,34 @@ public class ConsulAutoServiceRegistrationAutoConfiguration { } @Bean - public ConsulAutoServiceRegistrationListener consulAutoServiceRegistrationListener(ConsulAutoServiceRegistration registration) { + public ConsulAutoServiceRegistrationListener consulAutoServiceRegistrationListener( + ConsulAutoServiceRegistration registration) { return new ConsulAutoServiceRegistrationListener(registration); } @Bean @ConditionalOnMissingBean - public ConsulAutoRegistration consulRegistration(AutoServiceRegistrationProperties autoServiceRegistrationProperties, + public ConsulAutoRegistration consulRegistration( + AutoServiceRegistrationProperties autoServiceRegistrationProperties, ConsulDiscoveryProperties properties, ApplicationContext applicationContext, ObjectProvider> registrationCustomizers, ObjectProvider> managementRegistrationCustomizers, HeartbeatProperties heartbeatProperties) { - return ConsulAutoRegistration.registration(autoServiceRegistrationProperties, properties, - applicationContext, registrationCustomizers.getIfAvailable(), - managementRegistrationCustomizers.getIfAvailable(), - heartbeatProperties); + return ConsulAutoRegistration.registration(autoServiceRegistrationProperties, + properties, applicationContext, registrationCustomizers.getIfAvailable(), + managementRegistrationCustomizers.getIfAvailable(), heartbeatProperties); } @Configuration @ConditionalOnClass(ServletContext.class) protected static class ConsulServletConfiguration { + @Bean - public ConsulRegistrationCustomizer servletConsulCustomizer(ObjectProvider servletContext) { + public ConsulRegistrationCustomizer servletConsulCustomizer( + ObjectProvider servletContext) { return new ConsulServletRegistrationCustomizer(servletContext); } + } - } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationListener.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationListener.java index 765916d7..b085c3b2 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationListener.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationListener.java @@ -1,3 +1,19 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.consul.serviceregistry; import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext; @@ -6,10 +22,17 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; +/** + * Auto registers service upon web server initialization. + * + * @author Spencer Gibb + */ public class ConsulAutoServiceRegistrationListener implements SmartApplicationListener { + private final ConsulAutoServiceRegistration autoServiceRegistration; - public ConsulAutoServiceRegistrationListener(ConsulAutoServiceRegistration autoServiceRegistration) { + public ConsulAutoServiceRegistrationListener( + ConsulAutoServiceRegistration autoServiceRegistration) { this.autoServiceRegistration = autoServiceRegistration; } @@ -30,8 +53,9 @@ public class ConsulAutoServiceRegistrationListener implements SmartApplicationLi ApplicationContext context = event.getApplicationContext(); if (context instanceof ConfigurableWebServerApplicationContext) { - if ("management".equals( - ((ConfigurableWebServerApplicationContext) context).getServerNamespace())) { + if ("management" + .equals(((ConfigurableWebServerApplicationContext) context) + .getServerNamespace())) { return; } } @@ -44,4 +68,5 @@ public class ConsulAutoServiceRegistrationListener implements SmartApplicationLi public int getOrder() { return 0; } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulManagementRegistrationCustomizer.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulManagementRegistrationCustomizer.java index 28ad9b57..605ac333 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulManagementRegistrationCustomizer.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulManagementRegistrationCustomizer.java @@ -20,5 +20,11 @@ package org.springframework.cloud.consul.serviceregistry; * @author Alexey Savchuk (devpreview) */ public interface ConsulManagementRegistrationCustomizer { + + /** + * Customizes a registration. + * @param managementRegistration registration to customize + */ void customize(ConsulRegistration managementRegistration); + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulRegistration.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulRegistration.java index ade8e615..614ce9df 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulRegistration.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulRegistration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +16,23 @@ package org.springframework.cloud.consul.serviceregistry; -import org.springframework.cloud.client.DefaultServiceInstance; -import org.springframework.cloud.client.serviceregistry.Registration; - -import com.ecwid.consul.v1.agent.model.NewService; -import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; -import org.springframework.cloud.consul.discovery.ConsulServerUtils; - import java.net.URI; import java.util.Map; +import com.ecwid.consul.v1.agent.model.NewService; + +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; +import org.springframework.cloud.consul.discovery.ConsulServerUtils; + /** * @author Spencer Gibb */ public class ConsulRegistration implements Registration { private final NewService service; + private ConsulDiscoveryProperties properties; public ConsulRegistration(NewService service, ConsulDiscoveryProperties properties) { @@ -40,11 +41,11 @@ public class ConsulRegistration implements Registration { } public NewService getService() { - return service; + return this.service; } protected ConsulDiscoveryProperties getProperties() { - return properties; + return this.properties; } public String getInstanceId() { @@ -79,4 +80,5 @@ public class ConsulRegistration implements Registration { public Map getMetadata() { return ConsulServerUtils.getMetadata(getService().getTags()); } + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulRegistrationCustomizer.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulRegistrationCustomizer.java index 2496e313..fe932f48 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulRegistrationCustomizer.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulRegistrationCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,5 +20,7 @@ package org.springframework.cloud.consul.serviceregistry; * @author Piotr Wielgolaski */ public interface ConsulRegistrationCustomizer { + void customize(ConsulRegistration registration); + } diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistry.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistry.java index c842d34f..6bac930c 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistry.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,21 +18,21 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.List; +import com.ecwid.consul.ConsulException; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.QueryParams; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.NewService; +import com.ecwid.consul.v1.health.model.Check; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.cloud.consul.discovery.HeartbeatProperties; import org.springframework.cloud.consul.discovery.TtlScheduler; import org.springframework.util.ReflectionUtils; -import com.ecwid.consul.ConsulException; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.QueryParams; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.health.model.Check; -import com.ecwid.consul.v1.agent.model.NewService; - import static org.springframework.boot.actuate.health.Status.OUT_OF_SERVICE; import static org.springframework.boot.actuate.health.Status.UP; @@ -51,7 +51,9 @@ public class ConsulServiceRegistry implements ServiceRegistry> response = client.getHealthChecksForService(serviceId, QueryParams.DEFAULT); + Response> response = this.client.getHealthChecksForService(serviceId, + QueryParams.DEFAULT); List checks = response.getValue(); for (Check check : checks) { @@ -121,4 +132,5 @@ public class ConsulServiceRegistry implements ServiceRegistry servletContext; - public ConsulServletRegistrationCustomizer(ObjectProvider servletContext) { + public ConsulServletRegistrationCustomizer( + ObjectProvider servletContext) { this.servletContext = servletContext; } @Override public void customize(ConsulRegistration registration) { - if (servletContext == null) { + if (this.servletContext == null) { return; } - ServletContext sc = servletContext.getIfAvailable(); - if(sc != null - && StringUtils.hasText(sc.getContextPath()) + ServletContext sc = this.servletContext.getIfAvailable(); + if (sc != null && StringUtils.hasText(sc.getContextPath()) && StringUtils.hasText(sc.getContextPath().replaceAll("/", ""))) { List tags = registration.getService().getTags(); if (tags == null) { @@ -50,4 +52,5 @@ public class ConsulServletRegistrationCustomizer implements ConsulRegistrationCu registration.getService().setTags(tags); } } + } diff --git a/spring-cloud-consul-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-consul-discovery/src/main/resources/META-INF/spring.factories index d1d8101c..bb5f5e48 100644 --- a/spring-cloud-consul-discovery/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-consul-discovery/src/main/resources/META-INF/spring.factories @@ -4,8 +4,6 @@ org.springframework.cloud.consul.discovery.configclient.ConsulConfigServerAutoCo org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration,\ org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistryAutoConfiguration,\ org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration - - org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.consul.discovery.configclient.ConsulDiscoveryClientConfigServiceBootstrapConfiguration diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientAclTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientAclTests.java index 5deaef0a..d83d3f79 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientAclTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientAclTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; @@ -29,19 +30,17 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Spencer Gibb */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulDiscoveryClientAclTests.MyTestConfig.class, - properties = {"spring.application.name=testConsulDiscoveryAcl", - "spring.cloud.consul.discovery.preferIpAddress=true", - "consul.token=2d2e6b3b-1c82-40ab-8171-54609d8ad304"}, - webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = ConsulDiscoveryClientAclTests.MyTestConfig.class, properties = { + "spring.application.name=testConsulDiscoveryAcl", + "spring.cloud.consul.discovery.preferIpAddress=true", + "consul.token=2d2e6b3b-1c82-40ab-8171-54609d8ad304" }, webEnvironment = RANDOM_PORT) public class ConsulDiscoveryClientAclTests { @Autowired @@ -49,24 +48,25 @@ public class ConsulDiscoveryClientAclTests { @Test public void getInstancesForThisServiceWorks() { - List instances = discoveryClient.getInstances("testConsulDiscoveryAcl"); - assertNotNull("instances was null", instances); - assertFalse("instances was empty", instances.isEmpty()); + List instances = this.discoveryClient + .getInstances("testConsulDiscoveryAcl"); + assertThat(instances).as("instances was null").isNotNull(); + assertThat(instances.isEmpty()).as("instances was empty").isFalse(); } - @Test public void getInstancesForSecondServiceWorks() throws Exception { - new SpringApplicationBuilder(MyTestConfig.class) - .run("--spring.application.name=testSecondServiceAcl", - "--server.port=0", - "--spring.cloud.consul.discovery.preferIpAddress=true", - "--consul.token=2d2e6b3b-1c82-40ab-8171-54609d8ad304"); + new SpringApplicationBuilder(MyTestConfig.class).run( + "--spring.application.name=testSecondServiceAcl", "--server.port=0", + "--spring.cloud.consul.discovery.preferIpAddress=true", + "--consul.token=2d2e6b3b-1c82-40ab-8171-54609d8ad304"); - List instances = discoveryClient.getInstances("testSecondServiceAcl"); - assertNotNull("second service instances was null", instances); - assertFalse("second service instances was empty", instances.isEmpty()); + List instances = this.discoveryClient + .getInstances("testSecondServiceAcl"); + assertThat(instances).as("second service instances was null").isNotNull(); + assertThat(instances.isEmpty()).as("second service instances was empty") + .isFalse(); } @Configuration @@ -75,4 +75,5 @@ public class ConsulDiscoveryClientAclTests { public static class MyTestConfig { } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientCustomizedTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientCustomizedTests.java index 1bf77f80..1eded26b 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientCustomizedTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientCustomizedTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.util.Map; import org.apache.http.conn.util.InetAddressUtils; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -30,9 +31,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** @@ -40,13 +39,12 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @author Tim Ysewyn */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulDiscoveryClientCustomizedTests.MyTestConfig.class, - properties = { "spring.application.name=testConsulDiscovery2", +@SpringBootTest(classes = ConsulDiscoveryClientCustomizedTests.MyTestConfig.class, properties = { + "spring.application.name=testConsulDiscovery2", "spring.cloud.consul.discovery.instanceId=testConsulDiscovery2Id", "spring.cloud.consul.discovery.hostname=testConsulDiscovery2Host", "spring.cloud.consul.discovery.registerHealthCheck=false", - "spring.cloud.consul.discovery.tags=plaintag,foo=bar,foo2=bar2=baz2" }, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.tags=plaintag,foo=bar,foo2=bar2=baz2" }, webEnvironment = RANDOM_PORT) public class ConsulDiscoveryClientCustomizedTests { @Autowired @@ -54,42 +52,44 @@ public class ConsulDiscoveryClientCustomizedTests { @Test public void getInstancesForServiceWorks() { - List instances = discoveryClient.getInstances("consul"); - assertNotNull("instances was null", instances); - assertFalse("instances was empty", instances.isEmpty()); + List instances = this.discoveryClient.getInstances("consul"); + assertThat(instances).as("instances was null").isNotNull(); + assertThat(instances.isEmpty()).as("instances was empty").isFalse(); } private void assertNotIpAddress(ServiceInstance instance) { - assertFalse("host is an ip address", - InetAddressUtils.isIPv4Address(instance.getHost())); + assertThat(InetAddressUtils.isIPv4Address(instance.getHost())) + .as("host is an ip address").isFalse(); } @Test public void getMetadataWorks() throws InterruptedException { - List instances = discoveryClient + List instances = this.discoveryClient .getInstances("testConsulDiscovery2"); - assertNotNull("instances was null", instances); - assertFalse("instances was empty", instances.isEmpty()); + assertThat(instances).as("instances was null").isNotNull(); + assertThat(instances.isEmpty()).as("instances was empty").isFalse(); ServiceInstance instance = instances.get(0); assertInstance(instance); } private void assertInstance(ServiceInstance instance) { - assertEquals("instance id was wrong", "testConsulDiscovery2Id", instance.getInstanceId()); - assertEquals("service id was wrong", "testConsulDiscovery2", instance.getServiceId()); + assertThat(instance.getInstanceId()).as("instance id was wrong") + .isEqualTo("testConsulDiscovery2Id"); + assertThat(instance.getServiceId()).as("service id was wrong") + .isEqualTo("testConsulDiscovery2"); Map metadata = instance.getMetadata(); - assertNotNull("metadata was null", metadata); + assertThat(metadata).as("metadata was null").isNotNull(); String foo = metadata.get("foo"); - assertEquals("metadata key foo was wrong", "bar", foo); + assertThat(foo).as("metadata key foo was wrong").isEqualTo("bar"); String plaintag = metadata.get("plaintag"); - assertEquals("metadata key plaintag was wrong", "plaintag", plaintag); + assertThat(plaintag).as("metadata key plaintag was wrong").isEqualTo("plaintag"); String foo2 = metadata.get("foo2"); - assertEquals("metadata key foo2 was wrong", "bar2=baz2", foo2); + assertThat(foo2).as("metadata key foo2 was wrong").isEqualTo("bar2=baz2"); } @Configuration @@ -98,4 +98,5 @@ public class ConsulDiscoveryClientCustomizedTests { public static class MyTestConfig { } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientDefaultQueryTagTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientDefaultQueryTagTests.java index c148c0b5..c760b7d5 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientDefaultQueryTagTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientDefaultQueryTagTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,38 +19,33 @@ package org.springframework.cloud.consul.discovery; import java.util.Arrays; import java.util.List; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.agent.model.NewService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.agent.model.NewService; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasSize; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.MOCK; /** * @author Piotr Wielgolaski */ @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = MOCK, - classes = ConsulDiscoveryClientDefaultQueryTagTests.TestConfig.class, - properties = { - "spring.application.name=consulServiceDefaultTag", - "spring.cloud.consul.discovery.catalogServicesWatch.enabled=false", - "spring.cloud.consul.discovery.defaultQueryTag=intg"}) +@SpringBootTest(webEnvironment = MOCK, classes = ConsulDiscoveryClientDefaultQueryTagTests.TestConfig.class, properties = { + "spring.application.name=consulServiceDefaultTag", + "spring.cloud.consul.discovery.catalogServicesWatch.enabled=false", + "spring.cloud.consul.discovery.defaultQueryTag=intg" }) @DirtiesContext public class ConsulDiscoveryClientDefaultQueryTagTests { @@ -63,25 +58,27 @@ public class ConsulDiscoveryClientDefaultQueryTagTests { private ConsulClient consulClient; private NewService intgService = serviceForEnvironment("intg", 9081); + private NewService uatService = serviceForEnvironment("uat", 9080); @Before public void setUp() throws Exception { - consulClient.agentServiceRegister(intgService); - consulClient.agentServiceRegister(uatService); + this.consulClient.agentServiceRegister(this.intgService); + this.consulClient.agentServiceRegister(this.uatService); } @After public void tearDown() throws Exception { - consulClient.agentServiceDeregister(intgService.getId()); - consulClient.agentServiceDeregister(uatService.getId()); + this.consulClient.agentServiceDeregister(this.intgService.getId()); + this.consulClient.agentServiceDeregister(this.uatService.getId()); } @Test public void shouldReturnOnlyIntgInstance() { - List instances = discoveryClient.getInstances(NAME); - assertThat("instances was wrong size", instances, hasSize(1)); - assertThat("instance is not intg", instances.get(0).getMetadata(), hasEntry("intg", "intg")); + List instances = this.discoveryClient.getInstances(NAME); + assertThat(instances).as("instances was wrong size").hasSize(1); + assertThat(instances.get(0).getMetadata()).as("instance is not intg") + .containsEntry("intg", "intg"); } private NewService serviceForEnvironment(String env, int port) { @@ -100,4 +97,5 @@ public class ConsulDiscoveryClientDefaultQueryTagTests { protected static class TestConfig { } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientHttpsTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientHttpsTests.java index c653a6f0..0e88c18e 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientHttpsTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientHttpsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,11 @@ package org.springframework.cloud.consul.discovery; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -33,15 +29,16 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + /** * @author Glen Lockhart */ @RunWith(SpringRunner.class) @SpringBootTest(properties = { "spring.application.name=testConsulDiscoveryHttps", - "spring.cloud.consul.discovery.prefer-ip-address=true", - "spring.cloud.consul.discovery.scheme=https"}, - classes = ConsulDiscoveryClientHttpsTests.MyTestConfig.class, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.prefer-ip-address=true", + "spring.cloud.consul.discovery.scheme=https" }, classes = ConsulDiscoveryClientHttpsTests.MyTestConfig.class, webEnvironment = RANDOM_PORT) public class ConsulDiscoveryClientHttpsTests { @Autowired @@ -49,12 +46,13 @@ public class ConsulDiscoveryClientHttpsTests { @Test public void getInstancesForServiceWorks() { - List instances = discoveryClient.getInstances("testConsulDiscoveryHttps"); - assertNotNull("instances was null", instances); - assertFalse("instances was empty", instances.isEmpty()); + List instances = this.discoveryClient + .getInstances("testConsulDiscoveryHttps"); + assertThat(instances).as("instances was null").isNotNull(); + assertThat(instances.isEmpty()).as("instances was empty").isFalse(); ServiceInstance instance = instances.get(0); - assertTrue("instance was not secure (https)", instance.isSecure()); + assertThat(instance.isSecure()).as("instance was not secure (https)").isTrue(); } @Configuration @@ -63,4 +61,5 @@ public class ConsulDiscoveryClientHttpsTests { public static class MyTestConfig { } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientTests.java index c27ecad2..79caaeb4 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,14 @@ package org.springframework.cloud.consul.discovery; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - import java.util.List; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.QueryParams; +import com.ecwid.consul.v1.Response; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -34,9 +32,8 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.QueryParams; -import com.ecwid.consul.v1.Response; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Spencer Gibb @@ -45,46 +42,46 @@ import com.ecwid.consul.v1.Response; @RunWith(SpringRunner.class) @SpringBootTest(properties = { "spring.application.name=testConsulDiscovery", "spring.cloud.consul.discovery.prefer-ip-address=true", - "spring.cloud.consul.discovery.tags=foo=bar", }, - classes = ConsulDiscoveryClientTests.MyTestConfig.class, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.tags=foo=bar" }, classes = ConsulDiscoveryClientTests.MyTestConfig.class, webEnvironment = RANDOM_PORT) public class ConsulDiscoveryClientTests { @Autowired private ConsulDiscoveryClient discoveryClient; + @Autowired private ConsulClient consulClient; @Test public void getInstancesForServiceWorks() { - List instances = discoveryClient.getInstances("testConsulDiscovery"); - assertNotNull("instances was null", instances); - assertFalse("instances was empty", instances.isEmpty()); + List instances = this.discoveryClient + .getInstances("testConsulDiscovery"); + assertThat(instances).as("instances was null").isNotNull(); + assertThat(instances.isEmpty()).as("instances was empty").isFalse(); ServiceInstance instance = instances.get(0); - assertFalse("instance was secure (https)", instance.isSecure()); + assertThat(instance.isSecure()).as("instance was secure (https)").isFalse(); assertIpAddress(instance); - assertThat(instance.getMetadata()) - .containsEntry("foo", "bar"); + assertThat(instance.getMetadata()).containsEntry("foo", "bar"); } @Test public void getInstancesForServiceRespectsQueryParams() { - Response> catalogDatacenters = consulClient.getCatalogDatacenters(); + Response> catalogDatacenters = this.consulClient + .getCatalogDatacenters(); List dataCenterList = catalogDatacenters.getValue(); - assertFalse("no data centers found", dataCenterList.isEmpty()); - List instances = discoveryClient.getInstances("testConsulDiscovery", - new QueryParams(dataCenterList.get(0))); - assertFalse("instances was empty", instances.isEmpty()); + assertThat(dataCenterList.isEmpty()).as("no data centers found").isFalse(); + List instances = this.discoveryClient.getInstances( + "testConsulDiscovery", new QueryParams(dataCenterList.get(0))); + assertThat(instances.isEmpty()).as("instances was empty").isFalse(); ServiceInstance instance = instances.get(0); assertIpAddress(instance); } private void assertIpAddress(ServiceInstance instance) { - assertTrue("host isn't an ip address", - Character.isDigit(instance.getHost().charAt(0))); + assertThat(Character.isDigit(instance.getHost().charAt(0))) + .as("host isn't an ip address").isTrue(); } @Configuration @@ -93,4 +90,5 @@ public class ConsulDiscoveryClientTests { public static class MyTestConfig { } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryPropertiesTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryPropertiesTests.java index c863f272..609de5a0 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryPropertiesTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryPropertiesTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.consul.discovery; import java.util.Collections; @@ -10,59 +26,73 @@ import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.commons.util.InetUtilsProperties; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; public class ConsulDiscoveryPropertiesTests { private static final String DEFAULT_TAG = "defaultTag"; + private static final String MAP_TAG = "mapTag"; + private static final String MAP_DC = "mapDc"; + private static final String SERVICE_NAME_IN_MAP = "serviceNameInMap"; + private static final String SERVICE_NAME_NOT_IN_MAP = "serviceNameNotInMap"; + + private final Map serverListQueryTags = Collections + .singletonMap(SERVICE_NAME_IN_MAP, MAP_TAG); + + private final Map datacenters = Collections + .singletonMap(SERVICE_NAME_IN_MAP, MAP_DC); + private ConsulDiscoveryProperties properties; - private final Map serverListQueryTags = Collections.singletonMap(SERVICE_NAME_IN_MAP, MAP_TAG); - private final Map datacenters = Collections.singletonMap(SERVICE_NAME_IN_MAP, MAP_DC); @Before public void setUp() { - properties = new ConsulDiscoveryProperties(new InetUtils(new InetUtilsProperties())); - properties.setDefaultQueryTag(DEFAULT_TAG); - properties.setServerListQueryTags(serverListQueryTags); - properties.setDatacenters(datacenters); + this.properties = new ConsulDiscoveryProperties( + new InetUtils(new InetUtilsProperties())); + this.properties.setDefaultQueryTag(DEFAULT_TAG); + this.properties.setServerListQueryTags(this.serverListQueryTags); + this.properties.setDatacenters(this.datacenters); } @Test public void testReturnsNullWhenNoDefaultAndNotInMap() { - properties.setDefaultQueryTag(null); + this.properties.setDefaultQueryTag(null); - assertNull(properties.getQueryTagForService(SERVICE_NAME_NOT_IN_MAP)); + assertThat(this.properties.getQueryTagForService(SERVICE_NAME_NOT_IN_MAP)) + .isNull(); } @Test public void testGetTagReturnsDefaultWhenNotInMap() { - assertEquals(DEFAULT_TAG, properties.getQueryTagForService(SERVICE_NAME_NOT_IN_MAP)); + assertThat(this.properties.getQueryTagForService(SERVICE_NAME_NOT_IN_MAP)) + .isEqualTo(DEFAULT_TAG); } @Test public void testGetTagReturnsMapValueWhenInMap() { - assertEquals(MAP_TAG, properties.getQueryTagForService(SERVICE_NAME_IN_MAP)); + assertThat(this.properties.getQueryTagForService(SERVICE_NAME_IN_MAP)) + .isEqualTo(MAP_TAG); } @Test public void testGetDcReturnsNullWhenNotInMap() { - assertNull(properties.getDatacenters().get(SERVICE_NAME_NOT_IN_MAP)); + assertThat(this.properties.getDatacenters().get(SERVICE_NAME_NOT_IN_MAP)) + .isNull(); } @Test public void testGetDcReturnsMapValueWhenInMap() { - assertEquals(MAP_DC, properties.getDatacenters().get(SERVICE_NAME_IN_MAP)); + assertThat(this.properties.getDatacenters().get(SERVICE_NAME_IN_MAP)) + .isEqualTo(MAP_DC); } @Test public void testAddManagementTag() { - properties.getManagementTags().add("newTag"); - assertThat(properties.getManagementTags()) + this.properties.getManagementTags().add("newTag"); + assertThat(this.properties.getManagementTags()) .containsOnly(ConsulDiscoveryProperties.MANAGEMENT, "newTag"); } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulLoadbalancerClientTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulLoadbalancerClientTests.java index d6867892..3960cf31 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulLoadbalancerClientTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulLoadbalancerClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertTrue; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** @@ -42,8 +41,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @RunWith(SpringRunner.class) @SpringBootTest(properties = { "spring.application.name=testConsulLoadBalancer", "spring.cloud.consul.discovery.prefer-ip-address=true", - "spring.cloud.consul.discovery.tags=foo=bar", }, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.tags=foo=bar" }, webEnvironment = RANDOM_PORT) public class ConsulLoadbalancerClientTests { @Autowired @@ -51,25 +49,26 @@ public class ConsulLoadbalancerClientTests { @Test public void chooseWorks() { - ServiceInstance instance = client.choose("testConsulLoadBalancer"); + ServiceInstance instance = this.client.choose("testConsulLoadBalancer"); assertThat(instance).isNotNull(); assertThat(instance.isSecure()).isFalse(); assertIpAddress(instance); - assertThat(instance.getMetadata()) - .containsEntry("foo", "bar"); + assertThat(instance.getMetadata()).containsEntry("foo", "bar"); } private void assertIpAddress(ServiceInstance instance) { - assertTrue("host isn't an ip address", - Character.isDigit(instance.getHost().charAt(0))); + assertThat(Character.isDigit(instance.getHost().charAt(0))) + .as("host isn't an ip address").isTrue(); } @SpringBootConfiguration @EnableAutoConfiguration @EnableDiscoveryClient @RibbonClient(name = "testConsulLoadBalancer", configuration = MyRibbonConfig.class) - public static class MyTestConfig { } + public static class MyTestConfig { + + } public static class MyRibbonConfig { @@ -81,5 +80,7 @@ public class ConsulLoadbalancerClientTests { public ServerListFilter ribbonServerListFilter() { return servers -> servers; } + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerListAclTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerListAclTests.java index 6d6b4805..fd10c392 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerListAclTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerListAclTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,11 @@ package org.springframework.cloud.consul.discovery; import java.util.List; +import com.ecwid.consul.v1.ConsulClient; +import com.netflix.client.config.DefaultClientConfigImpl; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -27,45 +30,42 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.netflix.client.config.DefaultClientConfigImpl; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** - * @author bomee + * @author b omee */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulServerListAclTests.TestConfig.class, - properties = {"spring.application.name=testConsulServerListAcl", - "spring.cloud.consul.discovery.preferIpAddress=true", - "consul.token=2d2e6b3b-1c82-40ab-8171-54609d8ad304"}, - webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = ConsulServerListAclTests.TestConfig.class, properties = { + "spring.application.name=testConsulServerListAcl", + "spring.cloud.consul.discovery.preferIpAddress=true", + "consul.token=2d2e6b3b-1c82-40ab-8171-54609d8ad304" }, webEnvironment = RANDOM_PORT) public class ConsulServerListAclTests { - @Autowired - private ConsulClient consulClient; + @Autowired + private ConsulClient consulClient; - @Autowired - private ConsulDiscoveryProperties properties; + @Autowired + private ConsulDiscoveryProperties properties; - @Test - public void serverListWorksWithAcl() { - ConsulServerList consulServerList = new ConsulServerList(consulClient, properties); - DefaultClientConfigImpl config = new DefaultClientConfigImpl(); - config.setClientName("testConsulServerListAcl"); - consulServerList.initWithNiwsConfig(config); - List servers = consulServerList.getUpdatedListOfServers(); - assertNotNull("servers was null", servers); - assertFalse("servers was empty", servers.isEmpty()); - } + @Test + public void serverListWorksWithAcl() { + ConsulServerList consulServerList = new ConsulServerList(this.consulClient, + this.properties); + DefaultClientConfigImpl config = new DefaultClientConfigImpl(); + config.setClientName("testConsulServerListAcl"); + consulServerList.initWithNiwsConfig(config); + List servers = consulServerList.getUpdatedListOfServers(); + assertThat(servers).as("servers was null").isNotNull(); + assertThat(servers.isEmpty()).as("servers was empty").isFalse(); + } - @Configuration - @EnableAutoConfiguration - @EnableDiscoveryClient - public static class TestConfig { + @Configuration + @EnableAutoConfiguration + @EnableDiscoveryClient + public static class TestConfig { + + } - } } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerListTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerListTests.java index 5e68d276..d158a86a 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerListTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerListTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,22 +20,21 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; -import org.junit.Test; -import org.springframework.cloud.commons.util.InetUtils; -import org.springframework.cloud.commons.util.InetUtilsProperties; - import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.agent.model.NewService; import com.netflix.client.config.DefaultClientConfigImpl; +import org.junit.Test; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.cloud.commons.util.InetUtilsProperties; + +import static org.assertj.core.api.Assertions.assertThat; /** * @author Spencer Gibb */ public class ConsulServerListTests { + private final String name = "consulServerListTestsService"; @Test @@ -48,10 +47,12 @@ public class ConsulServerListTests { NewService tagged = createService("Tagged", 9080, Arrays.asList(tag)); String zone = "myzone"; - NewService withZone = createService("WithZone", 10080, Arrays.asList("zone=" + zone)); + NewService withZone = createService("WithZone", 10080, + Arrays.asList("zone=" + zone)); String group = "test"; - NewService withGroup = createService("WithGroup", 11080, Arrays.asList("group=" + group)); + NewService withGroup = createService("WithGroup", 11080, + Arrays.asList("group=" + group)); try { consul.agentServiceRegister(nonTagged); @@ -61,43 +62,51 @@ public class ConsulServerListTests { InetUtils inetUtils = new InetUtils(new InetUtilsProperties()); DefaultClientConfigImpl config = new DefaultClientConfigImpl(); - config.setClientName(name); + config.setClientName(this.name); - ConsulServerList serverList = new ConsulServerList(consul, new ConsulDiscoveryProperties(inetUtils)); + ConsulServerList serverList = new ConsulServerList(consul, + new ConsulDiscoveryProperties(inetUtils)); serverList.initWithNiwsConfig(config); List servers = serverList.getInitialListOfServers(); - assertThat("servers was wrong size", servers, hasSize(4)); + assertThat(servers).as("servers was wrong size").hasSize(4); int serverWithZoneCount = 0; for (ConsulServer server : servers) { if (server.getMetadata().containsKey("zone")) { serverWithZoneCount++; - assertThat("server was wrong zone", server.getZone(), is(zone)); - } else { - assertThat("server was wrong zone", server.getZone(), is(ConsulServer.UNKNOWN_ZONE)); + assertThat(server.getZone()).as("server was wrong zone") + .isEqualTo(zone); + } + else { + assertThat(server.getZone()).as("server was wrong zone") + .isEqualTo(ConsulServer.UNKNOWN_ZONE); } } - assertThat("server was wrong zone", serverWithZoneCount, is(1)); + assertThat(serverWithZoneCount).as("server was wrong zone").isEqualTo(1); - serverList = new ConsulServerList(consul, getProperties(name, tag, inetUtils)); + serverList = new ConsulServerList(consul, + getProperties(this.name, tag, inetUtils)); serverList.initWithNiwsConfig(config); servers = serverList.getInitialListOfServers(); - assertThat("servers was wrong size", servers, hasSize(1)); + assertThat(servers).as("servers was wrong size").hasSize(1); ConsulServer server = servers.get(0); - assertThat("server was wrong", server.getPort(), is(9080)); + assertThat(server.getPort()).as("server was wrong").isEqualTo(9080); // test server group - serverList = new ConsulServerList(consul, getProperties(name, "group=" + group, inetUtils)); + serverList = new ConsulServerList(consul, + getProperties(this.name, "group=" + group, inetUtils)); serverList.initWithNiwsConfig(config); servers = serverList.getInitialListOfServers(); - assertThat("servers was wrong size", servers, hasSize(1)); + assertThat(servers).as("servers was wrong size").hasSize(1); server = servers.get(0); - assertThat("server was wrong", server.getPort(), is(11080)); - assertThat("server group was wrong", server.getMetaInfo().getServerGroup(), is(group)); - } finally { + assertThat(server.getPort()).as("server was wrong").isEqualTo(11080); + assertThat(server.getMetaInfo().getServerGroup()).as("server group was wrong") + .isEqualTo(group); + } + finally { consul.agentServiceDeregister(nonTagged.getId()); consul.agentServiceDeregister(tagged.getId()); consul.agentServiceDeregister(withZone.getId()); @@ -105,7 +114,8 @@ public class ConsulServerListTests { } } - private ConsulDiscoveryProperties getProperties(String name, String tag, InetUtils inetUtils) { + private ConsulDiscoveryProperties getProperties(String name, String tag, + InetUtils inetUtils) { ConsulDiscoveryProperties properties = new ConsulDiscoveryProperties(inetUtils); HashMap map = new HashMap<>(); map.put(name, tag); @@ -115,8 +125,8 @@ public class ConsulServerListTests { private NewService createService(String id, int port, List tags) { NewService service = new NewService(); - service.setName(name); - service.setId(name + id); + service.setName(this.name); + service.setId(this.name + id); service.setAddress("localhost"); service.setPort(port); if (tags != null) { @@ -124,4 +134,5 @@ public class ConsulServerListTests { } return service; } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerUtilsTest.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerUtilsTest.java index f34b8472..755f94a0 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerUtilsTest.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulServerUtilsTest.java @@ -1,8 +1,24 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.consul.discovery; import org.junit.Test; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Semenkov Alexey @@ -12,19 +28,20 @@ public class ConsulServerUtilsTest { @Test public void testAddressFormat() { String s1 = ConsulServerUtils.fixIPv6Address("fc00:ec:cd::242:ac11:c"); - assertEquals("[fc00:ec:cd:0:0:242:ac11:c]", s1); + assertThat(s1).isEqualTo("[fc00:ec:cd:0:0:242:ac11:c]"); String s2 = ConsulServerUtils.fixIPv6Address("[fc00:ec:cd::242:ac11:c]"); - assertEquals("[fc00:ec:cd:0:0:242:ac11:c]", s2); + assertThat(s2).isEqualTo("[fc00:ec:cd:0:0:242:ac11:c]"); String s3 = ConsulServerUtils.fixIPv6Address("192.168.0.1"); - assertEquals("192.168.0.1", s3); + assertThat(s3).isEqualTo("192.168.0.1"); String s4 = ConsulServerUtils.fixIPv6Address("projects.spring.io"); - assertEquals("projects.spring.io", s4); + assertThat(s4).isEqualTo("projects.spring.io"); String s5 = ConsulServerUtils.fixIPv6Address("veryLongHostName"); - assertEquals("veryLongHostName", s5); + assertThat(s5).isEqualTo("veryLongHostName"); } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/HealthServiceServerListFilterTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/HealthServiceServerListFilterTests.java index dd3a7609..7162d694 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/HealthServiceServerListFilterTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/HealthServiceServerListFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,12 +22,12 @@ import java.util.List; import com.ecwid.consul.v1.health.model.Check; import com.ecwid.consul.v1.health.model.HealthService; import com.netflix.loadbalancer.Server; - import org.junit.Test; -import static com.ecwid.consul.v1.health.model.Check.CheckStatus.*; -import static org.junit.Assert.assertThat; -import static org.hamcrest.Matchers.*; +import static com.ecwid.consul.v1.health.model.Check.CheckStatus.CRITICAL; +import static com.ecwid.consul.v1.health.model.Check.CheckStatus.PASSING; +import static com.ecwid.consul.v1.health.model.Check.CheckStatus.WARNING; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Spencer Gibb @@ -45,20 +45,20 @@ public class HealthServiceServerListFilterTests { servers.add(newServer(WARNING)); List filtered = filter.getFilteredListOfServers(servers); - assertThat("wrong # of filtered servers", filtered, hasSize(2)); + assertThat(filtered).as("wrong # of filtered servers").hasSize(2); } private ConsulServer newServer(Check.CheckStatus checkStatus) { HealthService healthService = new HealthService(); HealthService.Node node = new HealthService.Node(); - node.setAddress("nodeaddr"+checkStatus.name()); - node.setNode("nodenode"+checkStatus.name()); + node.setAddress("nodeaddr" + checkStatus.name()); + node.setNode("nodenode" + checkStatus.name()); healthService.setNode(node); HealthService.Service service = new HealthService.Service(); - service.setAddress("serviceaddr"+checkStatus.name()); - service.setId("serviceid"+checkStatus.name()); + service.setAddress("serviceaddr" + checkStatus.name()); + service.setId("serviceid" + checkStatus.name()); service.setPort(8080); - service.setService("serviceservice"+checkStatus.name()); + service.setService("serviceservice" + checkStatus.name()); healthService.setService(service); ArrayList checks = new ArrayList<>(); Check check = new Check(); @@ -67,4 +67,5 @@ public class HealthServiceServerListFilterTests { healthService.setChecks(checks); return new ConsulServer(healthService); } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/HeartbeatPropertiesTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/HeartbeatPropertiesTests.java index bfdb5023..dcf7bacd 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/HeartbeatPropertiesTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/HeartbeatPropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,35 +16,33 @@ package org.springframework.cloud.consul.discovery; -import static org.junit.Assert.assertThat; -import static org.hamcrest.Matchers.*; - import org.joda.time.Period; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Spencer Gibb */ public class HeartbeatPropertiesTests { - @Test - public void computeHeartbeatIntervalWorks() { - HeartbeatProperties properties = new HeartbeatProperties(); - Period period = properties.computeHearbeatInterval(); + @Test + public void computeHeartbeatIntervalWorks() { + HeartbeatProperties properties = new HeartbeatProperties(); + Period period = properties.computeHearbeatInterval(); - assertThat(period, is(notNullValue())); - assertThat(period.getSeconds(), is(20)); - } + assertThat(period).isNotNull(); + assertThat(period.getSeconds()).isEqualTo(20); + } - @Test - public void computeShortHeartbeat() { - HeartbeatProperties properties = new HeartbeatProperties(); - properties.setTtlValue(2); - Period period = properties.computeHearbeatInterval(); - - assertThat(period, is(notNullValue())); - assertThat(period.getSeconds(), is(1)); - } + @Test + public void computeShortHeartbeat() { + HeartbeatProperties properties = new HeartbeatProperties(); + properties.setTtlValue(2); + Period period = properties.computeHearbeatInterval(); + assertThat(period).isNotNull(); + assertThat(period.getSeconds()).isEqualTo(1); + } } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/TtlSchedulerRemoveTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/TtlSchedulerRemoveTests.java index c796ebcd..37a2b361 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/TtlSchedulerRemoveTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/TtlSchedulerRemoveTests.java @@ -1,9 +1,30 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.consul.discovery; import java.util.List; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.QueryParams; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.health.model.Check; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -13,27 +34,20 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.QueryParams; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.health.model.Check; - import static com.ecwid.consul.v1.health.model.Check.CheckStatus.CRITICAL; import static com.ecwid.consul.v1.health.model.Check.CheckStatus.PASSING; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Stéphane Leroy */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = TtlSchedulerRemoveTests.TtlSchedulerRemoveTestConfig.class, - properties = { "spring.application.name=ttlSchedulerRemove", +@SpringBootTest(classes = TtlSchedulerRemoveTests.TtlSchedulerRemoveTestConfig.class, properties = { + "spring.application.name=ttlSchedulerRemove", "spring.cloud.consul.discovery.instance-id=ttlSchedulerRemove-id", "spring.cloud.consul.discovery.heartbeat.enabled=true", - "spring.cloud.consul.discovery.heartbeat.ttlValue=2" }, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.heartbeat.ttlValue=2" }, webEnvironment = RANDOM_PORT) public class TtlSchedulerRemoveTests { @Autowired @@ -46,20 +60,20 @@ public class TtlSchedulerRemoveTests { public void should_not_send_check_if_service_removed() throws InterruptedException { Thread.sleep(1000); // wait for Ttlscheduler to send a check to consul. Check serviceCheck = getCheckForService("ttlSchedulerRemove"); - assertThat("Service check is in wrong state", serviceCheck.getStatus(), - equalTo(PASSING)); + assertThat(serviceCheck.getStatus()).as("Service check is in wrong state") + .isEqualTo(PASSING); // Remove service from TtlScheduler and wait for TTL to expired. - ttlScheduler.remove("ttlSchedulerRemove-id"); + this.ttlScheduler.remove("ttlSchedulerRemove-id"); Thread.sleep(2100); serviceCheck = getCheckForService("ttlSchedulerRemove"); - assertThat("Service check is in wrong state", serviceCheck.getStatus(), - equalTo(CRITICAL)); + assertThat(serviceCheck.getStatus()).as("Service check is in wrong state") + .isEqualTo(CRITICAL); } private Check getCheckForService(String serviceId) { - Response> checkResponse = consul.getHealthChecksForService(serviceId, - QueryParams.DEFAULT); + Response> checkResponse = this.consul + .getHealthChecksForService(serviceId, QueryParams.DEFAULT); if (checkResponse.getValue().size() > 0) { return checkResponse.getValue().get(0); } @@ -68,9 +82,10 @@ public class TtlSchedulerRemoveTests { @Configuration @EnableAutoConfiguration - @Import({ AutoServiceRegistrationConfiguration.class, - ConsulAutoConfiguration.class, + @Import({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulDiscoveryClientConfiguration.class }) - public static class TtlSchedulerRemoveTestConfig { } -} + public static class TtlSchedulerRemoveTestConfig { + } + +} diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/TtlSchedulerTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/TtlSchedulerTests.java index 48f15a52..1a485343 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/TtlSchedulerTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/TtlSchedulerTests.java @@ -1,9 +1,30 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.cloud.consul.discovery; import java.util.List; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.QueryParams; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.health.model.Check; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -13,11 +34,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.QueryParams; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.health.model.Check; - import static com.ecwid.consul.v1.health.model.Check.CheckStatus.PASSING; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -26,12 +42,12 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @author Stéphane Leroy */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = TtlSchedulerTests.TtlSchedulerTestConfig.class, - properties = { "spring.application.name=ttlScheduler", +@SpringBootTest(classes = TtlSchedulerTests.TtlSchedulerTestConfig.class, properties = { + "spring.application.name=ttlScheduler", "spring.cloud.consul.discovery.instance-id=ttlScheduler-id", "spring.cloud.consul.discovery.heartbeat.enabled=true", - "spring.cloud.consul.discovery.heartbeat.ttlValue=2", "management.server.port=0" }, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.heartbeat.ttlValue=2", + "management.server.port=0" }, webEnvironment = RANDOM_PORT) public class TtlSchedulerTests { @Autowired @@ -53,8 +69,8 @@ public class TtlSchedulerTests { } private Check getCheckForService(String serviceId) { - Response> checkResponse = consul.getHealthChecksForService(serviceId, - QueryParams.DEFAULT); + Response> checkResponse = this.consul + .getHealthChecksForService(serviceId, QueryParams.DEFAULT); if (checkResponse.getValue().size() > 0) { return checkResponse.getValue().get(0); } @@ -63,10 +79,10 @@ public class TtlSchedulerTests { @Configuration @EnableAutoConfiguration - @Import({ AutoServiceRegistrationConfiguration.class, - ConsulAutoConfiguration.class, + @Import({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulDiscoveryClientConfiguration.class }) - public static class TtlSchedulerTestConfig { } + public static class TtlSchedulerTestConfig { + + } + } - - diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/ConsulConfigServerAutoConfigurationTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/ConsulConfigServerAutoConfigurationTests.java index 25760a71..ada9ac66 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/ConsulConfigServerAutoConfigurationTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/ConsulConfigServerAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.cloud.consul.discovery.configclient; import org.junit.After; import org.junit.Test; + import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; @@ -26,9 +27,7 @@ import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import static org.hamcrest.Matchers.contains; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Dave Syer @@ -48,25 +47,28 @@ public class ConsulConfigServerAutoConfigurationTests { public void offByDefault() throws Exception { this.context = new AnnotationConfigApplicationContext( ConsulConfigServerAutoConfiguration.class); - assertEquals(0, - this.context.getBeanNamesForType(ConsulDiscoveryProperties.class).length); + assertThat( + this.context.getBeanNamesForType(ConsulDiscoveryProperties.class).length) + .isEqualTo(0); } @Test public void onWhenRequested() throws Exception { setup("spring.cloud.config.server.prefix=/config"); - assertEquals(1, - this.context.getBeanNamesForType(ConsulDiscoveryProperties.class).length); - ConsulDiscoveryProperties properties = this.context.getBean(ConsulDiscoveryProperties.class); - assertThat(properties.getTags(), contains("configPath=/config")); + assertThat( + this.context.getBeanNamesForType(ConsulDiscoveryProperties.class).length) + .isEqualTo(1); + ConsulDiscoveryProperties properties = this.context + .getBean(ConsulDiscoveryProperties.class); + assertThat(properties.getTags()).containsExactly("configPath=/config"); } private void setup(String... env) { this.context = new SpringApplicationBuilder( PropertyPlaceholderAutoConfiguration.class, - ConsulConfigServerAutoConfiguration.class, - ConfigServerProperties.class, ConsulDiscoveryProperties.class).web(WebApplicationType.NONE) - .properties(env).run(); + ConsulConfigServerAutoConfiguration.class, ConfigServerProperties.class, + ConsulDiscoveryProperties.class).web(WebApplicationType.NONE) + .properties(env).run(); } } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/DiscoveryClientConfigServiceAutoConfigurationTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/DiscoveryClientConfigServiceAutoConfigurationTests.java index 58d75595..8e2eff06 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/DiscoveryClientConfigServiceAutoConfigurationTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/DiscoveryClientConfigServiceAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.AbstractApplicationContext; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.verify; @@ -47,7 +47,7 @@ public class DiscoveryClientConfigServiceAutoConfigurationTests { @Before public void init() { - //FIXME: why do I need to do this? (fails in maven build without it. + // FIXME: why do I need to do this? (fails in maven build without it. TomcatURLStreamHandlerFactory.disable(); } @@ -67,29 +67,30 @@ public class DiscoveryClientConfigServiceAutoConfigurationTests { "logging.level.org.springframework.cloud.config.client=DEBUG", "spring.cloud.consul.discovery.test.enabled:true", "spring.application.name=discoveryclientconfigservicetest", - "spring.jmx.enabled=false", - "spring.cloud.consul.discovery.port:7001", + "spring.jmx.enabled=false", "spring.cloud.consul.discovery.port:7001", "spring.cloud.consul.discovery.hostname:foo", "spring.cloud.config.discovery.service-id:configserver"); - assertEquals( 1, this.context - .getBeanNamesForType(ConsulConfigServerAutoConfiguration.class).length); - ConsulDiscoveryClient client = this.context.getParent().getBean( - ConsulDiscoveryClient.class); + assertThat(this.context + .getBeanNamesForType(ConsulConfigServerAutoConfiguration.class).length) + .isEqualTo(1); + ConsulDiscoveryClient client = this.context.getParent() + .getBean(ConsulDiscoveryClient.class); verify(client, atLeast(2)).getInstances("configserver"); ConfigClientProperties locator = this.context .getBean(ConfigClientProperties.class); - assertEquals("http://foo:7001/", locator.getUri()[0]); + assertThat(locator.getUri()[0]).isEqualTo("http://foo:7001/"); } private void setup(String... env) { - this.context = new SpringApplicationBuilder(TestConfig.class) - .properties(env) + this.context = new SpringApplicationBuilder(TestConfig.class).properties(env) .run(); } @Configuration @EnableAutoConfiguration - protected static class TestConfig { } + protected static class TestConfig { + + } } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/TestConsulDiscoveryClientBootstrapConfiguration.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/TestConsulDiscoveryClientBootstrapConfiguration.java index 7b5540f1..c13a7d2b 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/TestConsulDiscoveryClientBootstrapConfiguration.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/configclient/TestConsulDiscoveryClientBootstrapConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package org.springframework.cloud.consul.discovery.configclient; +import java.util.Arrays; + import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.ServiceInstance; @@ -24,8 +26,6 @@ import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Arrays; - import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -39,8 +39,8 @@ public class TestConsulDiscoveryClientBootstrapConfiguration { ConsulDiscoveryClient client = mock(ConsulDiscoveryClient.class); ServiceInstance instance = new DefaultServiceInstance("configserver", properties.getHostname(), properties.getPort(), false); - given(client.getInstances("configserver")) - .willReturn(Arrays.asList(instance)); + given(client.getInstances("configserver")).willReturn(Arrays.asList(instance)); return client; } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistrationHealthCheckHeadersTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistrationHealthCheckHeadersTests.java index 9ff390db..7de5e4a9 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistrationHealthCheckHeadersTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistrationHealthCheckHeadersTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,10 @@ package org.springframework.cloud.consul.serviceregistry; -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - +import com.ecwid.consul.v1.agent.model.NewService; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -31,7 +30,8 @@ import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.agent.model.NewService; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Lomesh Patel @@ -69,5 +69,7 @@ public class ConsulAutoRegistrationHealthCheckHeadersTests { ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) public static class TestConfig { + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistrationHealthCheckTlsSkipVerifyTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistrationHealthCheckTlsSkipVerifyTests.java index 7714d91e..fbe15e30 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistrationHealthCheckTlsSkipVerifyTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoRegistrationHealthCheckTlsSkipVerifyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.cloud.consul.serviceregistry; import com.ecwid.consul.v1.agent.model.NewService; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -66,5 +67,7 @@ public class ConsulAutoRegistrationHealthCheckTlsSkipVerifyTests { ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) public static class TestConfig { + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceDeRegistrationDisabledTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceDeRegistrationDisabledTests.java index bc86eecb..6e027a65 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceDeRegistrationDisabledTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceDeRegistrationDisabledTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,14 @@ package org.springframework.cloud.consul.serviceregistry; +import java.util.Map; + import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.Response; import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -31,59 +34,62 @@ import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import java.util.Map; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Jon Freedman */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationDisabledTests.TestConfig.class, - properties = {"spring.application.name=myTestNotDeRegisteredService", - "spring.cloud.consul.discovery.instanceId=myTestNotDeRegisteredService-D", - "spring.cloud.consul.discovery.deregister=false"}, - webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = ConsulAutoServiceRegistrationDisabledTests.TestConfig.class, properties = { + "spring.application.name=myTestNotDeRegisteredService", + "spring.cloud.consul.discovery.instanceId=myTestNotDeRegisteredService-D", + "spring.cloud.consul.discovery.deregister=false" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceDeRegistrationDisabledTests { - @Autowired - private ConsulClient consul; - @Autowired(required = false) - private ConsulAutoServiceRegistration autoServiceRegistration; + @Autowired + private ConsulClient consul; - @Autowired(required = false) - private ConsulDiscoveryProperties discoveryProperties; + @Autowired(required = false) + private ConsulAutoServiceRegistration autoServiceRegistration; - @Test - public void contextLoads() { - assertNotNull("ConsulAutoServiceRegistration was not created", autoServiceRegistration); - assertNotNull("ConsulDiscoveryProperties was not created", discoveryProperties); + @Autowired(required = false) + private ConsulDiscoveryProperties discoveryProperties; - checkService(true); - autoServiceRegistration.deregister(); - checkService(true); - discoveryProperties.setDeregister(true); - autoServiceRegistration.deregister(); - checkService(false); - } + @Test + public void contextLoads() { + assertThat(this.autoServiceRegistration) + .as("ConsulAutoServiceRegistration was not created").isNotNull(); + assertThat(this.discoveryProperties) + .as("ConsulDiscoveryProperties was not created").isNotNull(); - private void checkService(final boolean expected) { - final Response> response = consul.getAgentServices(); - final Map services = response.getValue(); - final Service service = services.get("myTestNotDeRegisteredService-D"); - if (expected) { - assertNotNull("service was not registered", service); - } else { - assertNull("service was registered", service); - } - } + checkService(true); + this.autoServiceRegistration.deregister(); + checkService(true); + this.discoveryProperties.setDeregister(true); + this.autoServiceRegistration.deregister(); + checkService(false); + } + + private void checkService(final boolean expected) { + final Response> response = this.consul.getAgentServices(); + final Map services = response.getValue(); + final Service service = services.get("myTestNotDeRegisteredService-D"); + if (expected) { + assertThat(service).as("service was not registered").isNotNull(); + } + else { + assertThat(service).as("service was registered").isNull(); + } + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + public static class TestConfig { + + } - @Configuration - @EnableAutoConfiguration - @ImportAutoConfiguration({AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, - ConsulAutoServiceRegistrationAutoConfiguration.class}) - public static class TestConfig { - } } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedAgentAddressTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedAgentAddressTests.java index bd2ab02f..61716e30 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedAgentAddressTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedAgentAddressTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,12 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -30,45 +34,45 @@ import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.StringUtils; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Spencer Gibb */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedAgentAddressTests.TestConfig.class, - properties = { "spring.application.name=myTestService-AA", +@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedAgentAddressTests.TestConfig.class, properties = { + "spring.application.name=myTestService-AA", "spring.cloud.consul.discovery.instanceId=myTestService1-AA", "spring.cloud.consul.discovery.serviceName=myprefix-${spring.application.name}", - "spring.cloud.consul.discovery.preferAgentAddress=true"}, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.preferAgentAddress=true" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationCustomizedAgentAddressTests { @Autowired private ConsulClient consul; - + @Test public void contextLoads() { - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service service = services.get("myTestService1-AA"); - assertNotNull("service was null", service); - assertNotEquals("service port is 0", 0, service.getPort().intValue()); - assertEquals("service id was wrong", "myTestService1-AA", service.getId()); - assertEquals("service name was wrong", "myprefix-myTestService-AA", service.getService()); - assertTrue("service address must be empty", StringUtils.isEmpty(service.getAddress())); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort().intValue()).as("service port is 0").isNotEqualTo(0); + assertThat(service.getId()).as("service id was wrong") + .isEqualTo("myTestService1-AA"); + assertThat(service.getService()).as("service name was wrong") + .isEqualTo("myprefix-myTestService-AA"); + assertThat(StringUtils.isEmpty(service.getAddress())) + .as("service address must be empty").isTrue(); } @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) - public static class TestConfig { } + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + public static class TestConfig { + + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedDiscoveryPortTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedDiscoveryPortTests.java index ede0a2d3..c3798573 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedDiscoveryPortTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedDiscoveryPortTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,12 @@ package org.springframework.cloud.consul.serviceregistry; +import com.ecwid.consul.v1.agent.model.NewService; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -31,8 +33,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.SocketUtils; -import com.ecwid.consul.v1.agent.model.NewService; - import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; @@ -40,9 +40,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @author Spencer Gibb */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedDiscoveryPortTests.TestConfig.class, - properties = { "spring.application.name=myTestService-DiscoveryPort", }, - webEnvironment = DEFINED_PORT) +@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedDiscoveryPortTests.TestConfig.class, properties = { + "spring.application.name=myTestService-DiscoveryPort" }, webEnvironment = DEFINED_PORT) public class ConsulAutoServiceRegistrationCustomizedDiscoveryPortTests { @Autowired @@ -73,17 +72,21 @@ public class ConsulAutoServiceRegistrationCustomizedDiscoveryPortTests { NewService.Check check = service.getCheck(); assertThat(check).as("check was null").isNotNull(); - String httpCheck = String.format("%s://%s:%s%s", properties.getScheme(), - properties.getHostname(), properties.getPort(), - properties.getHealthCheckPath()); + String httpCheck = String.format("%s://%s:%s%s", this.properties.getScheme(), + this.properties.getHostname(), this.properties.getPort(), + this.properties.getHealthCheckPath()); assertThat(check.getHttp()).as("http check was wrong").isEqualTo(httpCheck); // unable to call consul api to get health check details } - @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) - public static class TestConfig { } + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + public static class TestConfig { + + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedInstanceGroupTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedInstanceGroupTests.java index d2906a49..5063390d 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedInstanceGroupTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedInstanceGroupTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,13 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.List; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; +import com.netflix.client.config.DefaultClientConfigImpl; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -33,26 +38,17 @@ import org.springframework.cloud.consul.discovery.ConsulServerList; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; -import com.netflix.client.config.DefaultClientConfigImpl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Jin Zhang */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedInstanceGroupTests.TestConfig.class, - properties = { "spring.application.name=myTestService-WithGroup", +@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedInstanceGroupTests.TestConfig.class, properties = { + "spring.application.name=myTestService-WithGroup", "spring.cloud.consul.discovery.instanceId=myTestService1-WithGroup", - "spring.cloud.consul.discovery.instanceGroup=test"}, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.instanceGroup=test" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationCustomizedInstanceGroupTests { @Autowired @@ -63,27 +59,34 @@ public class ConsulAutoServiceRegistrationCustomizedInstanceGroupTests { @Test public void contextLoads() { - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service service = services.get("myTestService1-WithGroup"); - assertNotNull("service was null", service); - assertNotEquals("service port is 0", 0, service.getPort().intValue()); - assertEquals("service id was wrong", "myTestService1-WithGroup", service.getId()); - assertTrue("service group was wrong", service.getTags().contains("group=test")); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort().intValue()).as("service port is 0").isNotEqualTo(0); + assertThat(service.getId()).as("service id was wrong") + .isEqualTo("myTestService1-WithGroup"); + assertThat(service.getTags().contains("group=test")).as("service group was wrong") + .isTrue(); - ConsulServerList serverList = new ConsulServerList(consul, properties); + ConsulServerList serverList = new ConsulServerList(this.consul, this.properties); DefaultClientConfigImpl config = new DefaultClientConfigImpl(); config.setClientName("myTestService-WithGroup"); serverList.initWithNiwsConfig(config); List servers = serverList.getInitialListOfServers(); - assertEquals("servers was wrong size", 1, servers.size()); - assertEquals("service group was wrong", "test", servers.get(0).getMetaInfo().getServerGroup()); + assertThat(servers.size()).as("servers was wrong size").isEqualTo(1); + assertThat(servers.get(0).getMetaInfo().getServerGroup()) + .as("service group was wrong").isEqualTo("test"); } - @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) - public static class TestConfig { } + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + public static class TestConfig { + + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedInstanceZoneTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedInstanceZoneTests.java index b02b0974..c7366769 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedInstanceZoneTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedInstanceZoneTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,12 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -29,26 +33,18 @@ import org.springframework.cloud.consul.ConsulAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Sixian Liu */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedInstanceZoneTests.TestConfig.class, - properties = { "spring.application.name=myTestService-WithZone", +@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedInstanceZoneTests.TestConfig.class, properties = { + "spring.application.name=myTestService-WithZone", "spring.cloud.consul.discovery.instanceId=myTestService1-WithZone", "spring.cloud.consul.discovery.instanceZone=zone1", - "spring.cloud.consul.discovery.defaultZoneMetadataName=myZone"}, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.defaultZoneMetadataName=myZone" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationCustomizedInstanceZoneTests { @Autowired @@ -56,17 +52,24 @@ public class ConsulAutoServiceRegistrationCustomizedInstanceZoneTests { @Test public void contextLoads() { - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service service = services.get("myTestService1-WithZone"); - assertNotNull("service was null", service); - assertNotEquals("service port is 0", 0, service.getPort().intValue()); - assertEquals("service id was wrong", "myTestService1-WithZone", service.getId()); - assertTrue("service zone was wrong", service.getTags().contains("myZone=zone1")); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort().intValue()).as("service port is 0").isNotEqualTo(0); + assertThat(service.getId()).as("service id was wrong") + .isEqualTo("myTestService1-WithZone"); + assertThat(service.getTags().contains("myZone=zone1")) + .as("service zone was wrong").isTrue(); } @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) - public static class TestConfig { } + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + public static class TestConfig { + + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedManagementServicePortTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedManagementServicePortTests.java index ef650a3f..f0ea3c93 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedManagementServicePortTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedManagementServicePortTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,14 @@ package org.springframework.cloud.consul.serviceregistry; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertFalse; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -38,9 +36,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.StringUtils; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Aleksandr Tarasov (aatarasov) @@ -68,35 +65,37 @@ public class ConsulAutoServiceRegistrationCustomizedManagementServicePortTests { @Test public void contextLoads() { - final Response> response = consul.getAgentServices(); + final Response> response = this.consul.getAgentServices(); final Map services = response.getValue(); final Service service = services.get("myTestService1-GG"); - assertNotNull("service was null", service); - assertNotEquals("service port was 0", 0, service.getPort().intValue()); - assertEquals("service id was wrong", "myTestService1-GG", service.getId()); - assertEquals("service name was wrong", "myprefix-myTestService-GG", - service.getService()); - assertFalse("service address must not be empty", - StringUtils.isEmpty(service.getAddress())); - assertEquals("service address must equals hostname from discovery properties", - discoveryProperties.getHostname(), service.getAddress()); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort().intValue()).as("service port was 0").isNotEqualTo(0); + assertThat(service.getId()).as("service id was wrong") + .isEqualTo("myTestService1-GG"); + assertThat(service.getService()).as("service name was wrong") + .isEqualTo("myprefix-myTestService-GG"); + assertThat(StringUtils.isEmpty(service.getAddress())) + .as("service address must not be empty").isFalse(); + assertThat(service.getAddress()) + .as("service address must equals hostname from discovery properties") + .isEqualTo(this.discoveryProperties.getHostname()); final Service managementService = services.get("myTestService1-GG-management"); - assertNotNull("management service was null", managementService); - assertEquals("management service port is not 4452", 4452, - managementService.getPort().intValue()); - assertEquals("management port is not 0", 0, - managementServerProperties.getPort().intValue()); - assertEquals("management service id was wrong", "myTestService1-GG-management", - managementService.getId()); - assertEquals("management service name was wrong", - "myprefix-myTestService-GG-management", managementService.getService()); - assertFalse("management service address must not be empty", - StringUtils.isEmpty(managementService.getAddress())); - assertEquals( - "management service address must equals hostname from discovery properties", - discoveryProperties.getHostname(), managementService.getAddress()); + assertThat(managementService).as("management service was null").isNotNull(); + assertThat(managementService.getPort().intValue()) + .as("management service port is not 4452").isEqualTo(4452); + assertThat(this.managementServerProperties.getPort().intValue()) + .as("management port is not 0").isEqualTo(0); + assertThat(managementService.getId()).as("management service id was wrong") + .isEqualTo("myTestService1-GG-management"); + assertThat(managementService.getService()).as("management service name was wrong") + .isEqualTo("myprefix-myTestService-GG-management"); + assertThat(StringUtils.isEmpty(managementService.getAddress())) + .as("management service address must not be empty").isFalse(); + assertThat(managementService.getAddress()).as( + "management service address must equals hostname from discovery properties") + .isEqualTo(this.discoveryProperties.getHostname()); } @Configuration @@ -105,5 +104,7 @@ public class ConsulAutoServiceRegistrationCustomizedManagementServicePortTests { ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) public static class TestConfig { + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedPropsTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedPropsTests.java index 38a0dc7e..24043a32 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedPropsTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedPropsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,14 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.List; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.QueryParams; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; +import com.ecwid.consul.v1.health.model.Check; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -31,18 +37,7 @@ import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.QueryParams; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; -import com.ecwid.consul.v1.health.model.Check; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** @@ -50,15 +45,14 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @author Venil Noronha */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedPropsTests.TestPropsConfig.class, - properties = { "spring.application.name=myTestService-B", +@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedPropsTests.TestPropsConfig.class, properties = { + "spring.application.name=myTestService-B", "spring.cloud.consul.discovery.instanceId=myTestService1-B", "spring.cloud.consul.discovery.port=4452", "spring.cloud.consul.discovery.hostname=myhost", "spring.cloud.consul.discovery.ipAddress=10.0.0.1", "spring.cloud.consul.discovery.registerHealthCheck=false", - "spring.cloud.consul.discovery.failFast=false" }, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.failFast=false" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationCustomizedPropsTests { @Autowired @@ -69,30 +63,42 @@ public class ConsulAutoServiceRegistrationCustomizedPropsTests { @Test public void contextLoads() { - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service service = services.get("myTestService1-B"); - assertThat("service was null", service, is(notNullValue())); - assertThat("service port is discovery port", service.getPort(), equalTo(4452)); - assertThat("service id was wrong", "myTestService1-B", equalTo(service.getId())); - assertThat("service name was wrong", "myTestService-B", equalTo(service.getService())); - assertThat("property hostname was wrong", "myhost", equalTo(this.properties.getHostname())); - assertThat("property ipAddress was wrong", "10.0.0.1", equalTo(this.properties.getIpAddress())); - assertThat("service address was wrong", "myhost", equalTo(service.getAddress())); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort()).as("service port is discovery port") + .isEqualTo(4452); + assertThat("myTestService1-B").as("service id was wrong") + .isEqualTo(service.getId()); + assertThat("myTestService-B").as("service name was wrong") + .isEqualTo(service.getService()); + assertThat("myhost").as("property hostname was wrong") + .isEqualTo(this.properties.getHostname()); + assertThat("10.0.0.1").as("property ipAddress was wrong") + .isEqualTo(this.properties.getIpAddress()); + assertThat("myhost").as("service address was wrong") + .isEqualTo(service.getAddress()); - Response> checkResponse = consul.getHealthChecksForService("myTestService-B", QueryParams.DEFAULT); + Response> checkResponse = this.consul + .getHealthChecksForService("myTestService-B", QueryParams.DEFAULT); List checks = checkResponse.getValue(); - assertThat("checks was wrong size", checks, hasSize(0)); + assertThat(checks).as("checks was wrong size").hasSize(0); } @Test public void testFailFastDisabled() { - assertFalse("property failFast was wrong", this.properties.isFailFast()); + assertThat(this.properties.isFailFast()).as("property failFast was wrong") + .isFalse(); } - @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) - public static class TestPropsConfig { } + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + public static class TestPropsConfig { + + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedServiceNameTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedServiceNameTests.java index f811467b..00e8bc7a 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedServiceNameTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedServiceNameTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,12 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -29,24 +33,17 @@ import org.springframework.cloud.consul.ConsulAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Spencer Gibb */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedServiceNameTests.TestConfig.class, - properties = { "spring.application.name=myTestService-CC", +@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedServiceNameTests.TestConfig.class, properties = { + "spring.application.name=myTestService-CC", "spring.cloud.consul.discovery.instanceId=myTestService1-CC", - "spring.cloud.consul.discovery.serviceName=myprefix-${spring.application.name}"}, - webEnvironment = RANDOM_PORT) + "spring.cloud.consul.discovery.serviceName=myprefix-${spring.application.name}" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationCustomizedServiceNameTests { @Autowired @@ -54,17 +51,24 @@ public class ConsulAutoServiceRegistrationCustomizedServiceNameTests { @Test public void contextLoads() { - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service service = services.get("myTestService1-CC"); - assertNotNull("service was null", service); - assertNotEquals("service port is 0", 0, service.getPort().intValue()); - assertEquals("service id was wrong", "myTestService1-CC", service.getId()); - assertEquals("service name was wrong", "myprefix-myTestService-CC", service.getService()); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort().intValue()).as("service port is 0").isNotEqualTo(0); + assertThat(service.getId()).as("service id was wrong") + .isEqualTo("myTestService1-CC"); + assertThat(service.getService()).as("service name was wrong") + .isEqualTo("myprefix-myTestService-CC"); } @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) - public static class TestConfig { } + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + public static class TestConfig { + + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedServletContextTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedServletContextTests.java index 0240e01f..64b1fcd0 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedServletContextTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedServletContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,12 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -27,10 +31,6 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; - import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -38,11 +38,10 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @author Piotr Wielgolaski */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedServletContextTests.TestConfig.class, - properties = { "spring.application.name=myTestService-WithServletContext", - "spring.cloud.consul.discovery.instanceId=myTestService1-WithServletContext", - "server.servlet.context-path=/customContext"}, - webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedServletContextTests.TestConfig.class, properties = { + "spring.application.name=myTestService-WithServletContext", + "spring.cloud.consul.discovery.instanceId=myTestService1-WithServletContext", + "server.servlet.context-path=/customContext" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationCustomizedServletContextTests { @Autowired @@ -50,17 +49,22 @@ public class ConsulAutoServiceRegistrationCustomizedServletContextTests { @Test public void contextLoads() { - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service service = services.get("myTestService1-WithServletContext"); assertThat(service).as("service was null").isNotNull(); assertThat(service.getPort().intValue()).as("service port is 0").isNotEqualTo(0); - assertThat(service.getId()).as("service id was wrong").isEqualTo("myTestService1-WithServletContext"); - assertThat(service.getTags()).as("contextPath tag missing").contains("contextPath=/customContext"); + assertThat(service.getId()).as("service id was wrong") + .isEqualTo("myTestService1-WithServletContext"); + assertThat(service.getTags()).as("contextPath tag missing") + .contains("contextPath=/customContext"); } @EnableDiscoveryClient @Configuration @EnableAutoConfiguration - public static class TestConfig { } + public static class TestConfig { + + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedTests.java index bc5115a1..397ac8d6 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationCustomizedTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.cloud.consul.serviceregistry; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -30,16 +31,15 @@ import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.context.annotation.Bean; import org.springframework.test.context.junit4.SpringRunner; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Marcin Biegan */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedTests.MyTestConfig.class, - properties = { "spring.application.name=testCustomAutoServiceRegistration"}, - webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = ConsulAutoServiceRegistrationCustomizedTests.MyTestConfig.class, properties = { + "spring.application.name=testCustomAutoServiceRegistration" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationCustomizedTests { @Autowired @@ -53,14 +53,19 @@ public class ConsulAutoServiceRegistrationCustomizedTests { @Test public void usesCustomConsulLifecycle() { - assertEquals("configuration is not customized", "customconfiguration", registration1.getConfiguration()); - assertEquals("configuration is not customized", "customconfiguration", registration2.getConfiguration()); + assertThat(this.registration1.getConfiguration()) + .as("configuration is not customized").isEqualTo("customconfiguration"); + assertThat(this.registration2.getConfiguration()) + .as("configuration is not customized").isEqualTo("customconfiguration"); } @SpringBootConfiguration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) public static class MyTestConfig { + @Bean public CustomAutoRegistration consulAutoServiceRegistration( ConsulServiceRegistry serviceRegistry, @@ -70,6 +75,7 @@ public class ConsulAutoServiceRegistrationCustomizedTests { return new CustomAutoRegistration(serviceRegistry, autoServiceRegistrationProperties, properties, registration); } + } public static class CustomAutoRegistration extends ConsulAutoServiceRegistration { @@ -87,5 +93,7 @@ public class ConsulAutoServiceRegistrationCustomizedTests { protected Object getConfiguration() { return "customconfiguration"; } + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDefaultCheckTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDefaultCheckTests.java index 7abc02c4..b9b9b80e 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDefaultCheckTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDefaultCheckTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,16 @@ package org.springframework.cloud.consul.serviceregistry; +import com.ecwid.consul.v1.ConsulClient; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationCustomizedPropsTests.TestPropsConfig; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; - import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -34,13 +34,12 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @deprecated remove in Edgware */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = TestPropsConfig.class, - properties = { "spring.application.name=myTestServiceDefaultChecks", - "spring.cloud.consul.discovery.instanceId=myTestServiceDefaultChecks", - "spring.cloud.consul.discovery.healthCheckCriticalTimeout=30m", - "spring.cloud.consul.discovery.healthCheckInterval=19s", - "spring.cloud.consul.discovery.healthCheckTimeout=12s", - }, webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = TestPropsConfig.class, properties = { + "spring.application.name=myTestServiceDefaultChecks", + "spring.cloud.consul.discovery.instanceId=myTestServiceDefaultChecks", + "spring.cloud.consul.discovery.healthCheckCriticalTimeout=30m", + "spring.cloud.consul.discovery.healthCheckInterval=19s", + "spring.cloud.consul.discovery.healthCheckTimeout=12s" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationDefaultCheckTests { @Autowired @@ -51,19 +50,25 @@ public class ConsulAutoServiceRegistrationDefaultCheckTests { @Test public void contextLoads() { - assertThat(properties.getHealthCheckCriticalTimeout()).isEqualTo("30m"); - assertThat(properties.getHealthCheckInterval()).isEqualTo("19s"); - assertThat(properties.getHealthCheckTimeout()).isEqualTo("12s"); + assertThat(this.properties.getHealthCheckCriticalTimeout()).isEqualTo("30m"); + assertThat(this.properties.getHealthCheckInterval()).isEqualTo("19s"); + assertThat(this.properties.getHealthCheckTimeout()).isEqualTo("12s"); - // I'm unable to find a way to query consul to see the configuration of the health check - // so for now, just sending the new healthCheckCriticalTimeout and having consul accept + // I'm unable to find a way to query consul to see the configuration of the health + // check + // so for now, just sending the new healthCheckCriticalTimeout and having consul + // accept // it is going to have to suffice - //final Response> checksForService = consul.getHealthChecksForService("myTestServiceDefaultChecks", QueryParams.DEFAULT); - //final List checkList = checksForService.getValue(); - //final Response> response2 = consul.getAgentChecks(); - //final Map checks = response2.getValue(); - //final Check check = checks.get("myTestServiceDefaultChecks"); - //Assertions.assertThat(check).isNotNull(); + // final Response> checksForService = + // consul.getHealthChecksForService("myTestServiceDefaultChecks", + // QueryParams.DEFAULT); + // final List checkList = + // checksForService.getValue(); + // final Response> response2 = consul.getAgentChecks(); + // final Map checks = response2.getValue(); + // final Check check = checks.get("myTestServiceDefaultChecks"); + // Assertions.assertThat(check).isNotNull(); } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDefaultPortTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDefaultPortTests.java index 40c84584..4c03c4ae 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDefaultPortTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDefaultPortTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,12 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -29,22 +33,16 @@ import org.springframework.cloud.consul.ConsulAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; - -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Spencer Gibb */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationDefaultPortTests.TestConfig.class, - properties = { "spring.application.name=myTestService2-DD", - "spring.cloud.consul.discovery.instanceId=myTestService2-DD", }, - webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = ConsulAutoServiceRegistrationDefaultPortTests.TestConfig.class, properties = { + "spring.application.name=myTestService2-DD", + "spring.cloud.consul.discovery.instanceId=myTestService2-DD" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationDefaultPortTests { @Autowired @@ -52,16 +50,20 @@ public class ConsulAutoServiceRegistrationDefaultPortTests { @Test public void contextLoads() { - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service service = services.get("myTestService2-DD"); - assertNotNull("service was null", service); - assertNotEquals("service port is 0", 0, service.getPort().intValue()); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort().intValue()).as("service port is 0").isNotEqualTo(0); } @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) - public static class TestConfig { } -} + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + public static class TestConfig { + } + +} diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDisabledTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDisabledTests.java index 6f873cf8..daa65415 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDisabledTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationDisabledTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,12 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -29,21 +33,16 @@ import org.springframework.cloud.consul.ConsulAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; - -import static org.junit.Assert.assertNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Spencer Gibb */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationDisabledTests.TestConfig.class, - properties = { "spring.application.name=myTestNotRegisteredService2", - "spring.cloud.service-registry.auto-registration.enabled=false"}, - webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = ConsulAutoServiceRegistrationDisabledTests.TestConfig.class, properties = { + "spring.application.name=myTestNotRegisteredService2", + "spring.cloud.service-registry.auto-registration.enabled=false" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationDisabledTests { @Autowired @@ -54,17 +53,22 @@ public class ConsulAutoServiceRegistrationDisabledTests { @Test public void contextLoads() { - assertNull("ConsulAutoServiceRegistration was created", autoServiceRegistration); + assertThat(this.autoServiceRegistration) + .as("ConsulAutoServiceRegistration was created").isNull(); - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service service = services.get("myTestNotRegisteredService2"); - assertNull("service was registered", service); + assertThat(service).as("service was registered").isNull(); } @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) - public static class TestConfig { } + public static class TestConfig { + + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationFailFastTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationFailFastTests.java index d91e1f5e..b46c645d 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationFailFastTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationFailFastTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,12 @@ package org.springframework.cloud.consul.serviceregistry; +import com.ecwid.consul.ConsulException; +import com.ecwid.consul.v1.ConsulClient; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -28,9 +31,6 @@ import org.springframework.cloud.consul.ConsulAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.test.annotation.DirtiesContext; -import com.ecwid.consul.ConsulException; -import com.ecwid.consul.v1.ConsulClient; - /** * @author Spencer Gibb * @author Venil Noronha @@ -44,20 +44,25 @@ public class ConsulAutoServiceRegistrationFailFastTests { @Test public void testFailFastEnabled() { this.exception.expect(ConsulException.class); - new SpringApplicationBuilder(TestConfig.class).properties("spring.application.name=testregistrationfails-fast", - "spring.jmx.default-domain=testautoregfailfast", - "server.port=0", "spring.cloud.consul.discovery.failFast=true").run(); + new SpringApplicationBuilder(TestConfig.class) + .properties("spring.application.name=testregistrationfails-fast", + "spring.jmx.default-domain=testautoregfailfast", "server.port=0", + "spring.cloud.consul.discovery.failFast=true") + .run(); } @SpringBootConfiguration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) protected static class TestConfig { @Bean public ConsulClient consulClient() { return new ConsulClient("localhost", 4321); } - } -} + } + +} diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementCustomizerTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementCustomizerTests.java index ec60e25e..f8f46331 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementCustomizerTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementCustomizerTests.java @@ -16,10 +16,14 @@ package org.springframework.cloud.consul.serviceregistry; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + import com.ecwid.consul.v1.agent.model.NewService; -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -30,10 +34,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** @@ -42,12 +43,10 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @RunWith(SpringRunner.class) @SpringBootTest(classes = { ConsulAutoServiceRegistrationManagementCustomizerTests.TestConfig.class, - ConsulAutoServiceRegistrationManagementCustomizerTests.ManagementConfig.class -}, properties = { - "spring.application.name=myTestService-SS", - "spring.cloud.consul.discovery.registerHealthCheck=false", - "management.server.port=4453" -}, webEnvironment = RANDOM_PORT) + ConsulAutoServiceRegistrationManagementCustomizerTests.ManagementConfig.class }, properties = { + "spring.application.name=myTestService-SS", + "spring.cloud.consul.discovery.registerHealthCheck=false", + "management.server.port=4453" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationManagementCustomizerTests { @Autowired @@ -58,11 +57,17 @@ public class ConsulAutoServiceRegistrationManagementCustomizerTests { @Test public void contextLoads() { - ConsulAutoRegistration managementRegistration = autoRegistration.managementRegistration(); + ConsulAutoRegistration managementRegistration = this.autoRegistration + .managementRegistration(); List checks = managementRegistration.getService().getChecks(); - List ttls = checks.stream().map(NewService.Check::getTtl).collect(Collectors.toList()); - Assert.assertTrue("Management registration not customized with 'foo' customizer", ttls.contains("39s")); - Assert.assertTrue("Management registration not customized with 'bar' customizer", ttls.contains("36s")); + List ttls = checks.stream().map(NewService.Check::getTtl) + .collect(Collectors.toList()); + assertThat(ttls.contains("39s")) + .as("Management registration not customized with 'foo' customizer") + .isTrue(); + assertThat(ttls.contains("36s")) + .as("Management registration not customized with 'bar' customizer") + .isTrue(); } @Configuration @@ -86,7 +91,8 @@ public class ConsulAutoServiceRegistrationManagementCustomizerTests { NewService managementService = managementRegistration.getService(); NewService.Check check = new NewService.Check(); check.setTtl(ttl); - List checks = managementService.getChecks() != null ? new ArrayList<>(managementService.getChecks()) : new ArrayList<>(); + List checks = managementService.getChecks() != null + ? new ArrayList<>(managementService.getChecks()) : new ArrayList<>(); checks.add(check); managementRegistration.getService().setChecks(checks); } @@ -95,11 +101,11 @@ public class ConsulAutoServiceRegistrationManagementCustomizerTests { @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({ - AutoServiceRegistrationConfiguration.class, + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, - ConsulAutoServiceRegistrationAutoConfiguration.class - }) + ConsulAutoServiceRegistrationAutoConfiguration.class }) public static class TestConfig { + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementDisabledServiceTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementDisabledServiceTests.java index 029e5025..c51647d3 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementDisabledServiceTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementDisabledServiceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,12 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -31,15 +35,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.StringUtils; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** @@ -62,21 +58,24 @@ public class ConsulAutoServiceRegistrationManagementDisabledServiceTests { @Test public void contextLoads() { - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service mgmtService = services.get("myTestService-NM-0-management"); - assertNull("Management service was not null", mgmtService); + assertThat(mgmtService).as("Management service was not null").isNull(); Service service = services.get("myTestService1-NM"); - assertNotNull("Service was not null", service); - assertNotEquals("service port was 0", 0, service.getPort().intValue()); - assertEquals("service id was wrong", "myTestService1-NM", service.getId()); - assertEquals("service name was wrong", "myTestService-NM", service.getService()); - assertFalse("service address must not be empty", - StringUtils.isEmpty(service.getAddress())); - assertEquals("service address must equals hostname from discovery properties", - discoveryProperties.getHostname(), service.getAddress()); + assertThat(service).as("Service was not null").isNotNull(); + assertThat(service.getPort().intValue()).as("service port was 0").isNotEqualTo(0); + assertThat(service.getId()).as("service id was wrong") + .isEqualTo("myTestService1-NM"); + assertThat(service.getService()).as("service name was wrong") + .isEqualTo("myTestService-NM"); + assertThat(StringUtils.isEmpty(service.getAddress())) + .as("service address must not be empty").isFalse(); + assertThat(service.getAddress()) + .as("service address must equals hostname from discovery properties") + .isEqualTo(this.discoveryProperties.getHostname()); } @@ -86,5 +85,7 @@ public class ConsulAutoServiceRegistrationManagementDisabledServiceTests { ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) public static class TestConfig { + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementServiceTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementServiceTests.java index ab3a7c43..52250cd2 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementServiceTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationManagementServiceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,14 @@ package org.springframework.cloud.consul.serviceregistry; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertFalse; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -37,9 +35,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.StringUtils; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** * @author Aleksandr Tarasov (aatarasov) @@ -60,32 +57,35 @@ public class ConsulAutoServiceRegistrationManagementServiceTests { @Test public void contextLoads() { - final Response> response = consul.getAgentServices(); + final Response> response = this.consul.getAgentServices(); final Map services = response.getValue(); final Service service = services.get("myTestService-EE-0"); - assertNotNull("service was null", service); - assertNotEquals("service port was 0", 0, service.getPort().intValue()); - assertEquals("service id was wrong", "myTestService-EE-0", service.getId()); - assertEquals("service name was wrong", "myTestService-EE", service.getService()); - assertFalse("service address must not be empty", - StringUtils.isEmpty(service.getAddress())); - assertEquals("service address must equals hostname from discovery properties", - discoveryProperties.getHostname(), service.getAddress()); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort().intValue()).as("service port was 0").isNotEqualTo(0); + assertThat(service.getId()).as("service id was wrong") + .isEqualTo("myTestService-EE-0"); + assertThat(service.getService()).as("service name was wrong") + .isEqualTo("myTestService-EE"); + assertThat(StringUtils.isEmpty(service.getAddress())) + .as("service address must not be empty").isFalse(); + assertThat(service.getAddress()) + .as("service address must equals hostname from discovery properties") + .isEqualTo(this.discoveryProperties.getHostname()); final Service managementService = services.get("myTestService-EE-0-management"); - assertNotNull("management service was null", managementService); - assertEquals("management service port was wrong", 4452, - managementService.getPort().intValue()); - assertEquals("management service id was wrong", "myTestService-EE-0-management", - managementService.getId()); - assertEquals("management service name was wrong", "myTestService-EE-management", - managementService.getService()); - assertFalse("management service address must not be empty", - StringUtils.isEmpty(managementService.getAddress())); - assertEquals( - "management service address must equals hostname from discovery properties", - discoveryProperties.getHostname(), managementService.getAddress()); + assertThat(managementService).as("management service was null").isNotNull(); + assertThat(managementService.getPort().intValue()) + .as("management service port was wrong").isEqualTo(4452); + assertThat(managementService.getId()).as("management service id was wrong") + .isEqualTo("myTestService-EE-0-management"); + assertThat(managementService.getService()).as("management service name was wrong") + .isEqualTo("myTestService-EE-management"); + assertThat(StringUtils.isEmpty(managementService.getAddress())) + .as("management service address must not be empty").isFalse(); + assertThat(managementService.getAddress()).as( + "management service address must equals hostname from discovery properties") + .isEqualTo(this.discoveryProperties.getHostname()); } @Configuration @@ -94,5 +94,7 @@ public class ConsulAutoServiceRegistrationManagementServiceTests { ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) public static class TestConfig { + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationNonWebTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationNonWebTests.java index 9337e61f..593cbf98 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationNonWebTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationNonWebTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,12 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -27,21 +31,16 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; /** * @author Spencer Gibb */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = ConsulAutoServiceRegistrationNonWebTests.TestConfig.class, - properties = { "spring.application.name=consulNonWebTest", "server.port=32111" }, - webEnvironment = NONE) +@SpringBootTest(classes = ConsulAutoServiceRegistrationNonWebTests.TestConfig.class, properties = { + "spring.application.name=consulNonWebTest", + "server.port=32111" }, webEnvironment = NONE) public class ConsulAutoServiceRegistrationNonWebTests { @Autowired @@ -52,16 +51,22 @@ public class ConsulAutoServiceRegistrationNonWebTests { @Test public void contextLoads() { - assertNotNull("ConsulAutoServiceRegistration was created", autoServiceRegistration); + assertThat(this.autoServiceRegistration) + .as("ConsulAutoServiceRegistration was created").isNotNull(); - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); Service service = services.get("consulNonWebTest"); - assertNull("service was registered", service); //no port to listen, hence no registration + assertThat(service).as("service was registered").isNull(); // no port to listen, + // hence no + // registration } @EnableDiscoveryClient @Configuration @EnableAutoConfiguration - public static class TestConfig { } + public static class TestConfig { + + } + } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationRetryTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationRetryTests.java index bfd9bb6d..15ee2334 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationRetryTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationRetryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,24 +50,30 @@ public class ConsulAutoServiceRegistrationRetryTests { @Test public void testRetry() { this.exception.expect(ConsulException.class); - try (ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfig.class).properties("spring.application.name=testregistrationretry", - "spring.jmx.default-domain=testautoregretry", - "spring.cloud.consul.retry.max-attempts=2", - "logging.level.org.springframework.retry=DEBUG", - "server.port=0").run()) { - output.expect(Matchers.containsString("Retry: count=")); + try (ConfigurableApplicationContext context = new SpringApplicationBuilder( + TestConfig.class) + .properties("spring.application.name=testregistrationretry", + "spring.jmx.default-domain=testautoregretry", + "spring.cloud.consul.retry.max-attempts=2", + "logging.level.org.springframework.retry=DEBUG", + "server.port=0") + .run()) { + this.output.expect(Matchers.containsString("Retry: count=")); } } @SpringBootConfiguration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) protected static class TestConfig { @Bean public ConsulClient consulClient() { return new ConsulClient("localhost", 4321); } - } -} + } + +} diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationTests.java index 9f08ffde..3f31f819 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,12 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Map; +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.Response; +import com.ecwid.consul.v1.agent.model.Service; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -31,14 +35,7 @@ import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.StringUtils; -import com.ecwid.consul.v1.ConsulClient; -import com.ecwid.consul.v1.Response; -import com.ecwid.consul.v1.agent.model.Service; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; import static org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration.normalizeForDns; @@ -47,8 +44,8 @@ import static org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistr * @author Venil Noronha */ @RunWith(SpringRunner.class) -@SpringBootTest(properties = { "spring.application.name=myTestService1-FF::something" }, - webEnvironment = RANDOM_PORT) +@SpringBootTest(properties = { + "spring.application.name=myTestService1-FF::something" }, webEnvironment = RANDOM_PORT) public class ConsulAutoServiceRegistrationTests { @Autowired @@ -62,23 +59,30 @@ public class ConsulAutoServiceRegistrationTests { @Test public void contextLoads() { - Response> response = consul.getAgentServices(); + Response> response = this.consul.getAgentServices(); Map services = response.getValue(); - Service service = services.get(registration.getInstanceId()); - assertNotNull("service was null", service); - assertNotEquals("service port is 0", 0, service.getPort().intValue()); - assertFalse("service id contained invalid character: " + service.getId(), service.getId().contains(":")); - assertEquals("service id was wrong", registration.getInstanceId(), service.getId()); - assertEquals("service name was wrong", "myTestService1-FF-something", service.getService()); - assertFalse("service address must not be empty", StringUtils.isEmpty(service.getAddress())); - assertEquals("service address must equals hostname from discovery properties", discoveryProperties.getHostname(), service.getAddress()); + Service service = services.get(this.registration.getInstanceId()); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort().intValue()).as("service port is 0").isNotEqualTo(0); + assertThat(service.getId().contains(":")) + .as("service id contained invalid character: " + service.getId()) + .isFalse(); + assertThat(service.getId()).as("service id was wrong") + .isEqualTo(this.registration.getInstanceId()); + assertThat(service.getService()).as("service name was wrong") + .isEqualTo("myTestService1-FF-something"); + assertThat(StringUtils.isEmpty(service.getAddress())) + .as("service address must not be empty").isFalse(); + assertThat(service.getAddress()) + .as("service address must equals hostname from discovery properties") + .isEqualTo(this.discoveryProperties.getHostname()); } @Test public void normalizeForDnsWorks() { - assertEquals("abc1", normalizeForDns("abc1")); - assertEquals("ab-c1", normalizeForDns("ab:c1")); - assertEquals("ab-c1", normalizeForDns("ab::c1")); + assertThat(normalizeForDns("abc1")).isEqualTo("abc1"); + assertThat(normalizeForDns("ab:c1")).isEqualTo("ab-c1"); + assertThat(normalizeForDns("ab::c1")).isEqualTo("ab-c1"); } @Test(expected = IllegalArgumentException.class) @@ -98,7 +102,11 @@ public class ConsulAutoServiceRegistrationTests { @SpringBootConfiguration @EnableAutoConfiguration - @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class }) - protected static class TestConfig { } -} + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + protected static class TestConfig { + } + +} diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistryCheckTtlTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistryCheckTtlTests.java index 57e82ebc..76ae4142 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistryCheckTtlTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistryCheckTtlTests.java @@ -16,9 +16,13 @@ package org.springframework.cloud.consul.serviceregistry; +import java.lang.reflect.Field; +import java.util.Map; + import com.ecwid.consul.v1.agent.model.NewService; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; @@ -31,11 +35,7 @@ import org.springframework.cloud.consul.discovery.TtlScheduler; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import java.lang.reflect.Field; -import java.util.Map; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Alexey Savchuk @@ -43,8 +43,7 @@ import static org.junit.Assert.assertTrue; @RunWith(SpringRunner.class) @SpringBootTest(classes = ConsulServiceRegistryCheckTtlTests.TestConfig.class, properties = { "spring.application.name=myTestService-S", - "spring.cloud.consul.discovery.heartbeat.enabled=true" -}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) + "spring.cloud.consul.discovery.heartbeat.enabled=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class ConsulServiceRegistryCheckTtlTests { @LocalServerPort @@ -63,38 +62,42 @@ public class ConsulServiceRegistryCheckTtlTests { private TtlScheduler ttlScheduler; private ConsulRegistration createHttpRegistration() { - NewService service = registration.getService(); + NewService service = this.registration.getService(); NewService.Check httpCheck = new NewService.Check(); - httpCheck.setHttp(String.format( - "%s://%s:%s%s", - discoveryProperties.getScheme(), - discoveryProperties.getHostname(), - randomServerPort, - discoveryProperties.getHealthCheckPath() - )); - httpCheck.setInterval(discoveryProperties.getHealthCheckInterval()); + httpCheck.setHttp( + String.format("%s://%s:%s%s", this.discoveryProperties.getScheme(), + this.discoveryProperties.getHostname(), this.randomServerPort, + this.discoveryProperties.getHealthCheckPath())); + httpCheck.setInterval(this.discoveryProperties.getHealthCheckInterval()); NewService httpService = new NewService(); httpService.setId(service.getId() + "-http"); httpService.setName(service.getName() + "-http"); httpService.setCheck(httpCheck); - return new ConsulRegistration(httpService, discoveryProperties); + return new ConsulRegistration(httpService, this.discoveryProperties); } @Test public void contextLoads() throws NoSuchFieldException, IllegalAccessException { ConsulRegistration httpRegistration = createHttpRegistration(); - consulServiceRegistry.register(httpRegistration); - Field serviceHeartbeatsField = TtlScheduler.class.getDeclaredField("serviceHeartbeats"); + this.consulServiceRegistry.register(httpRegistration); + Field serviceHeartbeatsField = TtlScheduler.class + .getDeclaredField("serviceHeartbeats"); serviceHeartbeatsField.setAccessible(true); - Map serviceHeartbeats = (Map) serviceHeartbeatsField.get(ttlScheduler); - assertTrue("Service with heartbeat check not registered in TTL scheduler", serviceHeartbeats.keySet().contains(registration.getInstanceId())); - assertFalse("Service with HTTP check registered in TTL scheduler", serviceHeartbeats.keySet().contains(httpRegistration.getInstanceId())); + Map serviceHeartbeats = (Map) serviceHeartbeatsField.get(this.ttlScheduler); + assertThat(serviceHeartbeats.keySet().contains(this.registration.getInstanceId())) + .as("Service with heartbeat check not registered in TTL scheduler") + .isTrue(); + assertThat(serviceHeartbeats.keySet().contains(httpRegistration.getInstanceId())) + .as("Service with HTTP check registered in TTL scheduler").isFalse(); } @Configuration @EnableAutoConfiguration - @ImportAutoConfiguration({AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, ConsulAutoServiceRegistrationAutoConfiguration.class}) + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, + ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) protected static class TestConfig { + } } diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistryTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistryTests.java index e3679d0c..8233e76f 100644 --- a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistryTests.java +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/serviceregistry/ConsulServiceRegistryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,21 +19,21 @@ package org.springframework.cloud.consul.serviceregistry; import java.util.Collections; import java.util.List; +import com.ecwid.consul.v1.agent.model.NewService; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.server.LocalServerPort; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.consul.discovery.ConsulDiscoveryClient; import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.test.context.junit4.SpringRunner; -import com.ecwid.consul.v1.agent.model.NewService; - import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -41,8 +41,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen * @author Spencer Gibb */ @RunWith(SpringRunner.class) -@SpringBootTest(properties = "spring.cloud.consul.discovery.query-passing=true", - webEnvironment = RANDOM_PORT) +@SpringBootTest(properties = "spring.cloud.consul.discovery.query-passing=true", webEnvironment = RANDOM_PORT) public class ConsulServiceRegistryTests { @Autowired(required = false) @@ -63,7 +62,8 @@ public class ConsulServiceRegistryTests { @Test public void contextLoads() { - assertThat(autoRegistration).as("autoRegistration created erroneously").isNull(); + assertThat(this.autoRegistration).as("autoRegistration created erroneously") + .isNull(); String serviceId = "myNonAutoRegisteredService"; @@ -71,28 +71,31 @@ public class ConsulServiceRegistryTests { service.setAddress("localhost"); service.setId("myNonAutoRegisteredService-A1"); service.setName(serviceId); - service.setPort(port); + service.setPort(this.port); service.setTags(Collections.singletonList("mytag")); - ConsulRegistration registration = new ConsulRegistration(service, this.properties); + ConsulRegistration registration = new ConsulRegistration(service, + this.properties); Throwable t = null; try { - serviceRegistry.register(registration); + this.serviceRegistry.register(registration); assertHasInstance(serviceId); assertStatus(registration, "UP"); // only works if query-passing = true - serviceRegistry.setStatus(registration, "OUT_OF_SERVICE"); + this.serviceRegistry.setStatus(registration, "OUT_OF_SERVICE"); assertEmptyInstances(serviceId); assertStatus(registration, "OUT_OF_SERVICE"); - serviceRegistry.setStatus(registration, "UP"); + this.serviceRegistry.setStatus(registration, "UP"); assertHasInstance(serviceId); - } catch (RuntimeException e) { - throw e ; - } finally { - serviceRegistry.deregister(registration); + } + catch (RuntimeException e) { + throw e; + } + finally { + this.serviceRegistry.deregister(registration); if (t == null) { // just deregister, test already failed assertEmptyInstances(serviceId); } @@ -101,12 +104,12 @@ public class ConsulServiceRegistryTests { } private void assertStatus(ConsulRegistration registration, String status) { - Object o = serviceRegistry.getStatus(registration); + Object o = this.serviceRegistry.getStatus(registration); assertThat(o).isEqualTo(status); } private void assertHasInstance(String serviceId) { - List instances = discoveryClient.getInstances(serviceId); + List instances = this.discoveryClient.getInstances(serviceId); assertThat(instances).hasSize(1); ServiceInstance instance = instances.get(0); @@ -114,13 +117,15 @@ public class ConsulServiceRegistryTests { } private void assertEmptyInstances(String serviceId) { - List instances = discoveryClient.getInstances(serviceId); + List instances = this.discoveryClient.getInstances(serviceId); assertThat(instances).isEmpty(); } @EnableDiscoveryClient(autoRegister = false) @SpringBootConfiguration @EnableAutoConfiguration - protected static class TestConfig { } -} + protected static class TestConfig { + } + +} diff --git a/spring-cloud-consul-sample/pom.xml b/spring-cloud-consul-sample/pom.xml index a060a20c..f65ef337 100644 --- a/spring-cloud-consul-sample/pom.xml +++ b/spring-cloud-consul-sample/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/spring-cloud-consul-sample/src/main/java/org/springframework/cloud/consul/sample/SampleConsulApplication.java b/spring-cloud-consul-sample/src/main/java/org/springframework/cloud/consul/sample/SampleConsulApplication.java index 86729546..5706d369 100644 --- a/spring-cloud-consul-sample/src/main/java/org/springframework/cloud/consul/sample/SampleConsulApplication.java +++ b/spring-cloud-consul-sample/src/main/java/org/springframework/cloud/consul/sample/SampleConsulApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ package org.springframework.cloud.consul.sample; import java.util.List; +import lombok.extern.slf4j.Slf4j; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; @@ -39,8 +41,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; -import lombok.extern.slf4j.Slf4j; - /** * @author Spencer Gibb */ @@ -50,7 +50,10 @@ import lombok.extern.slf4j.Slf4j; @EnableConfigurationProperties @EnableFeignClients @Slf4j -public class SampleConsulApplication /*implements ApplicationListener*/ { +public class SampleConsulApplication /* + * implements + * ApplicationListener + */ { @Autowired private LoadBalancerClient loadBalancer; @@ -73,6 +76,10 @@ public class SampleConsulApplication /*implements ApplicationListener instances() { - return discoveryClient.getInstances(appName); + return this.discoveryClient.getInstances(this.appName); } + /* + * @Bean public SubtypeModule sampleSubtypeModule() { return new + * SubtypeModule(SimpleRemoteEvent.class); } + */ + @RequestMapping("/feign") public String feign() { - return sampleClient.choose(); + return this.sampleClient.choose(); } - /*@Bean - public SubtypeModule sampleSubtypeModule() { - return new SubtypeModule(SimpleRemoteEvent.class); - }*/ - @Bean public SampleProperties sampleProperties() { return new SampleProperties(); @@ -129,20 +137,17 @@ public class SampleConsulApplication /*implements ApplicationListener - + 4.0.0 org.springframework.cloud diff --git a/spring-cloud-starter-consul-all/src/main/resources/META-INF/spring.provides b/spring-cloud-starter-consul-all/src/main/resources/META-INF/spring.provides index 18c222fc..7faec1ca 100644 --- a/spring-cloud-starter-consul-all/src/main/resources/META-INF/spring.provides +++ b/spring-cloud-starter-consul-all/src/main/resources/META-INF/spring.provides @@ -1 +1 @@ -provides: spring-cloud-consul-bus, spring-cloud-consul-config, spring-cloud-consul-discovery, spring-cloud-consul-ui \ No newline at end of file +provides: spring-cloud-consul-bus, spring-cloud-consul-config, spring-cloud-consul-discovery, spring-cloud-consul-ui diff --git a/spring-cloud-starter-consul-bus/pom.xml b/spring-cloud-starter-consul-bus/pom.xml index 3ce6fd81..b61e70b0 100644 --- a/spring-cloud-starter-consul-bus/pom.xml +++ b/spring-cloud-starter-consul-bus/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 org.springframework.cloud diff --git a/spring-cloud-starter-consul-bus/src/main/resources/META-INF/spring.provides b/spring-cloud-starter-consul-bus/src/main/resources/META-INF/spring.provides index 7e37bc1f..c6358bc1 100644 --- a/spring-cloud-starter-consul-bus/src/main/resources/META-INF/spring.provides +++ b/spring-cloud-starter-consul-bus/src/main/resources/META-INF/spring.provides @@ -1 +1 @@ -provides: spring-cloud-consul-bus \ No newline at end of file +provides: spring-cloud-consul-bus diff --git a/spring-cloud-starter-consul-config/pom.xml b/spring-cloud-starter-consul-config/pom.xml index d8556da2..03270d58 100644 --- a/spring-cloud-starter-consul-config/pom.xml +++ b/spring-cloud-starter-consul-config/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 org.springframework.cloud diff --git a/spring-cloud-starter-consul-config/src/main/resources/META-INF/spring.provides b/spring-cloud-starter-consul-config/src/main/resources/META-INF/spring.provides index 76b15afb..e7564ef7 100644 --- a/spring-cloud-starter-consul-config/src/main/resources/META-INF/spring.provides +++ b/spring-cloud-starter-consul-config/src/main/resources/META-INF/spring.provides @@ -1 +1 @@ -provides: spring-cloud-consul-config \ No newline at end of file +provides: spring-cloud-consul-config diff --git a/spring-cloud-starter-consul-discovery/pom.xml b/spring-cloud-starter-consul-discovery/pom.xml index efeac473..5ef278dd 100644 --- a/spring-cloud-starter-consul-discovery/pom.xml +++ b/spring-cloud-starter-consul-discovery/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/spring-cloud-starter-consul-discovery/src/main/resources/META-INF/spring.provides b/spring-cloud-starter-consul-discovery/src/main/resources/META-INF/spring.provides index 85fed12c..c0e57c89 100644 --- a/spring-cloud-starter-consul-discovery/src/main/resources/META-INF/spring.provides +++ b/spring-cloud-starter-consul-discovery/src/main/resources/META-INF/spring.provides @@ -1 +1 @@ -provides: spring-cloud-consul-discovery \ No newline at end of file +provides: spring-cloud-consul-discovery diff --git a/spring-cloud-starter-consul/pom.xml b/spring-cloud-starter-consul/pom.xml index ba32c33a..cc7a483b 100644 --- a/spring-cloud-starter-consul/pom.xml +++ b/spring-cloud-starter-consul/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 org.springframework.cloud diff --git a/spring-cloud-starter-consul/src/main/resources/META-INF/spring.provides b/spring-cloud-starter-consul/src/main/resources/META-INF/spring.provides index 174eee93..fe3abad3 100644 --- a/spring-cloud-starter-consul/src/main/resources/META-INF/spring.provides +++ b/spring-cloud-starter-consul/src/main/resources/META-INF/spring.provides @@ -1 +1 @@ -provides: spring-cloud-consul-core, consul-api \ No newline at end of file +provides: spring-cloud-consul-core, consul-api diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml new file mode 100644 index 00000000..34bb0712 --- /dev/null +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/src/main/bash/travis_install_consul.sh b/src/main/bash/travis_install_consul.sh index 588275ac..f5909ceb 100755 --- a/src/main/bash/travis_install_consul.sh +++ b/src/main/bash/travis_install_consul.sh @@ -1,6 +1,6 @@ #!/bin/bash -CONSUL_VER="0.7.5" +CONSUL_VER="1.4.2" CONSUL_ZIP="consul_${CONSUL_VER}_linux_amd64.zip" IGNORE_CERTS="${IGNORE_CERTS:-no}" diff --git a/src/test/resources/consul_acl/consul_anonymous_acl.json b/src/test/resources/consul_acl/consul_anonymous_acl.json index 61745b11..6d00484e 100644 --- a/src/test/resources/consul_acl/consul_anonymous_acl.json +++ b/src/test/resources/consul_acl/consul_anonymous_acl.json @@ -1,28 +1,31 @@ { - "ID": "anonymous", - "Name": "anonymous", - "Type": "client", - "Rules": "{ - \"key\": { - \"\": { - \"policy\": \"write\" - } - }, - \"event\": { - \"\": { - \"policy\": \"write\" - } - }, - \"service\": { - \"\": { - \"policy\": \"write\" - }, - \"testConsulDiscoveryAcl\": { - \"policy\": \"deny\" - }, - \"testConsulDiscoveryAcl\": { - \"policy\": \"deny\" - } - } - }" + "ID": "anonymous", + "Name": "anonymous", + "Type": "client", + "Rules": "{ + \ + "key\": { + \ + "\": { + \ + "policy\": \"write\" +} +}, +\"event\": { +\"\": { +\"policy\": \"write\" +} +}, +\"service\": { +\"\": { +\"policy\": \"write\" +}, +\"testConsulDiscoveryAcl\": { +\"policy\": \"deny\" +}, +\"testConsulDiscoveryAcl\": { +\"policy\": \"deny\" +} +} +}" } diff --git a/src/test/resources/consul_acl/consul_discovery_client_acl.json b/src/test/resources/consul_acl/consul_discovery_client_acl.json index 7af310a1..6ff52993 100644 --- a/src/test/resources/consul_acl/consul_discovery_client_acl.json +++ b/src/test/resources/consul_acl/consul_discovery_client_acl.json @@ -1,18 +1,21 @@ { - "ID": "2d2e6b3b-1c82-40ab-8171-54609d8ad304", - "Name": "discover_client_test_acl", - "Type": "client", - "Rules": "{ - \"service\": { - \"\": { - \"policy\": \"write\" - }, - \"testConsulDiscoveryAcl\": { - \"policy\": \"write\" - }, - \"testSecondServiceAcl\": { - \"policy\": \"write\" - } - } - }" + "ID": "2d2e6b3b-1c82-40ab-8171-54609d8ad304", + "Name": "discover_client_test_acl", + "Type": "client", + "Rules": "{ + \ + "service\": { + \ + "\": { + \ + "policy\": \"write\" +}, +\"testConsulDiscoveryAcl\": { +\"policy\": \"write\" +}, +\"testSecondServiceAcl\": { +\"policy\": \"write\" +} +} +}" } diff --git a/src/test/resources/consul_config/acl_config.json b/src/test/resources/consul_config/acl_config.json index ea9e761b..344f5a6a 100644 --- a/src/test/resources/consul_config/acl_config.json +++ b/src/test/resources/consul_config/acl_config.json @@ -1,6 +1,6 @@ { - "datacenter": "local", - "acl_datacenter": "local", - "acl_master_token": "2ee647bd-bd69-4118-9f34-b9a6e9e60746", - "acl_default_policy": "deny" + "datacenter": "local", + "acl_datacenter": "local", + "acl_master_token": "2ee647bd-bd69-4118-9f34-b9a6e9e60746", + "acl_default_policy": "deny" } diff --git a/src/test/resources/consul_ui/index.html b/src/test/resources/consul_ui/index.html index bfd9bf4c..bd9aa8f4 100644 --- a/src/test/resources/consul_ui/index.html +++ b/src/test/resources/consul_ui/index.html @@ -1,40 +1,43 @@ - - - - Consul by HashiCorp - - - + + + + Consul by HashiCorp + + + -
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
- + - - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + - + + + + + diff --git a/src/test/resources/consul_ui/static/application.min.js b/src/test/resources/consul_ui/static/application.min.js index 4055c2ba..413431fe 100644 --- a/src/test/resources/consul_ui/static/application.min.js +++ b/src/test/resources/consul_ui/static/application.min.js @@ -364,4 +364,4 @@ if ( typeof define === 'function' && define.amd ) { window.NotificationFx = NotificationFx; } )( window ); -window.App=Ember.Application.create({rootElement:"#app",currentPath:""}),Ember.Application.initializer({name:"settings",initialize:function(t,e){e.set("settings",App.Settings.create()),void 0===App.get("settings.token")&&App.set("settings.token","")}}),App.Router.map(function(){this.resource("dc",{path:"/:dc"},function(){this.resource("services",{path:"/services"},function(){this.route("show",{path:"/*name"})}),this.resource("nodes",{path:"/nodes"},function(){this.route("show",{path:"/:name"})}),this.resource("kv",{path:"/kv"},function(){this.route("index",{path:"/"}),this.route("show",{path:"/*key"}),this.route("edit",{path:"/*key/edit"})}),this.resource("acls",{path:"/acls"},function(){this.route("show",{path:"/:id"})}),this.route("aclsdisabled",{path:"/aclsdisabled"}),this.route("unauthorized",{path:"/unauthorized"}),this.resource("settings",{path:"/settings"})}),this.route("index",{path:"/"})});App.Service=Ember.Object.extend({failingChecks:function(){if(void 0!==this.get("ChecksCritical"))return this.get("ChecksCritical")+this.get("ChecksWarning");var e=this.get("Checks");return e.filterBy("Status","critical").get("length")+e.filterBy("Status","warning").get("length")}.property("Checks"),passingChecks:function(){return void 0!==this.get("ChecksPassing")?this.get("ChecksPassing"):this.get("Checks").filterBy("Status","passing").get("length")}.property("Checks"),checkMessage:function(){return this.get("hasFailingChecks")===!1?this.get("passingChecks")+" passing":this.get("failingChecks")+" failing"}.property("Checks"),nodes:function(){return this.get("Nodes")}.property("Nodes"),hasFailingChecks:Ember.computed.gt("failingChecks",0),filterKey:Ember.computed.alias("Name")}),App.Node=Ember.Object.extend({failingChecks:function(){return this.get("Checks").reduce(function(e,t){var r=Ember.get(t,"Status");return"critical"===r||"warning"===r?e+1:e},0)}.property("Checks"),passingChecks:function(){return this.get("Checks").filterBy("Status","passing").get("length")}.property("Checks"),checkMessage:function(){return this.get("hasFailingChecks")===!1?this.get("passingChecks")+" passing":this.get("failingChecks")+" failing"}.property("Checks"),hasFailingChecks:Ember.computed.gt("failingChecks",0),numServices:Ember.computed.alias("Services.length"),services:Ember.computed.alias("Services"),filterKey:Ember.computed.alias("Node")}),App.Key=Ember.Object.extend(Ember.Validations.Mixin,{validations:{Key:{presence:!0}},keyValid:Ember.computed.empty("errors.Key"),valueValid:Ember.computed.empty("errors.Value"),keyWithoutParent:function(){return this.get("Key").replace(this.get("parentKey"),"")}.property("Key"),isFolder:function(){return void 0===this.get("Key")?!1:"/"===this.get("Key").slice(-1)}.property("Key"),isLocked:function(){return this.get("Session")?!0:!1}.property("Session"),linkToRoute:function(){return"/"===this.get("Key").slice(-1)?"kv.show":"kv.edit"}.property("Key"),valueDecoded:function(e,t){return arguments.length>1?(this.set("Value",t),t):null===this.get("Value")?"":(Base64.extendString&&Base64.extendString(),this.get("Value").fromBase64())}.property("Value"),keyParts:function(){var e=this.get("Key");return"/"==e.slice(-1)&&(e=e.substring(0,e.length-1)),e.split("/")}.property("Key"),parentKey:function(){var e=this.get("keyParts").toArray();return e.pop(),e.join("/")+"/"}.property("Key"),grandParentKey:function(){var e=this.get("keyParts").toArray();return e.pop(),e.pop(),e.join("/")+"/"}.property("Key")}),App.Acl=Ember.Object.extend({isNotAnon:function(){return"anonymous"===this.get("ID")?!1:!0}.property("ID")}),App.Settings=Ember.Object.extend({unknownProperty:function(e){return localStorage[e]},setUnknownProperty:function(e,t){return Ember.isNone(t)?delete localStorage[e]:localStorage[e]=t,this.notifyPropertyChange(e),t},clear:function(){this.beginPropertyChanges();for(var e=0,t=localStorage.length;t>e;e++)this.set(localStorage.key(e));localStorage.clear(),this.endPropertyChanges()}});function formatUrl(e,t,n){return null==n&&(n=""),e.indexOf("?")>0?(e=e+"&dc="+t,e=e+"&token="+n):(e=e+"?dc="+t,e=e+"&token="+n),e}App.BaseRoute=Ember.Route.extend({rootKey:"",condensedView:!1,queryParams:{filter:{replace:!0}},getParentAndGrandparent:function(e){var t=this.rootKey,n=this.rootKey,o=e.split("/");return o.length>0&&(o.pop(),t=o.join("/")+"/"),o.length>1&&(o.pop(),n=o.join("/")+"/"),{parent:t,grandParent:n,isRoot:"/"===t}},removeDuplicateKeys:function(e,t){return e.forEach(function(n,o){n.get("Key")==t&&e.splice(o,1)}),e},actions:{linkToKey:function(e){"/"==e?this.transitionTo("kv.show",""):"/"===e.slice(-1)||e===this.rootKey?this.transitionTo("kv.show",e):this.transitionTo("kv.edit",e)}}}),App.IndexRoute=App.BaseRoute.extend({model:function(){return Ember.$.getJSON("/v1/catalog/datacenters").then(function(e){return e})},afterModel:function(e){1===e.get("length")&&this.transitionTo("services",e[0])}}),App.DcRoute=App.BaseRoute.extend({model:function(e){var t=App.get("settings.token");return Ember.RSVP.hash({dc:e.dc,dcs:Ember.$.getJSON("/v1/catalog/datacenters"),nodes:Ember.$.getJSON(formatUrl("/v1/internal/ui/nodes",e.dc,t)).then(function(e){var t=[];return e.map(function(e){t.push(App.Node.create(e))}),t})})},setupController:function(e,t){e.set("content",t.dc),e.set("nodes",t.nodes),e.set("dcs",t.dcs),e.set("isDropdownVisible",!1)}}),App.KvIndexRoute=App.BaseRoute.extend({beforeModel:function(){this.transitionTo("kv.show",this.rootKey)}}),App.KvShowRoute=App.BaseRoute.extend({model:function(e){var t=e.key,n=this.modelFor("dc").dc,o=App.get("settings.token");return Ember.RSVP.hash({key:t,keys:Ember.$.getJSON(formatUrl("/v1/kv/"+t+"?keys&seperator=/",n,o)).then(function(e){var t=[];return e.map(function(e){t.push(App.Key.create({Key:e}))}),t})})},setupController:function(e,t){var n=t.key,o=this.getParentAndGrandparent(n);t.keys=this.removeDuplicateKeys(t.keys,t.key),e.set("content",t.keys),e.set("parentKey",o.parent),e.set("grandParentKey",o.grandParent),e.set("isRoot",o.isRoot),e.set("newKey",App.Key.create()),e.set("rootKey",this.rootKey)}}),App.KvEditRoute=App.BaseRoute.extend({model:function(e){var t=e.key,n=this.modelFor("dc").dc,o=this.getParentAndGrandparent(t),r=App.get("settings.token");return Ember.RSVP.hash({dc:n,token:r,key:Ember.$.getJSON(formatUrl("/v1/kv/"+t,n,r)).then(function(e){return App.Key.create().setProperties(e[0])}),keys:keysPromise=Ember.$.getJSON(formatUrl("/v1/kv/"+o.parent+"?keys&seperator=/",n,r)).then(function(e){var t=[];return e.map(function(e){t.push(App.Key.create({Key:e}))}),t})})},afterModel:function(e){return e.key.get("isLocked")?Ember.$.getJSON(formatUrl("/v1/session/info/"+e.key.Session,e.dc,e.token)).then(function(t){return e.session=t[0],e}):e},setupController:function(e,t){var n=t.key,o=this.getParentAndGrandparent(n.get("Key"));t.keys=this.removeDuplicateKeys(t.keys,o.parent),e.set("content",t.key),e.set("parentKey",o.parent),e.set("grandParentKey",o.grandParent),e.set("isRoot",o.isRoot),e.set("siblings",t.keys),e.set("rootKey",this.rootKey),e.set("session",t.session)}}),App.ServicesRoute=App.BaseRoute.extend({model:function(){var e=this.modelFor("dc").dc,t=App.get("settings.token");return Ember.$.getJSON(formatUrl("/v1/internal/ui/services",e,t)).then(function(e){var t=[];return e.map(function(e){t.push(App.Service.create(e))}),t})},setupController:function(e,t){e.set("services",t)}}),App.ServicesShowRoute=App.BaseRoute.extend({model:function(e){var t=this.modelFor("dc").dc,n=App.get("settings.token");return Ember.$.getJSON(formatUrl("/v1/health/service/"+e.name,t,n)).then(function(e){var t=[];return e.map(function(e){t.push(App.Node.create(e))}),t})},setupController:function(e,t){var n=[];t.map(function(e){n=n.concat(e.Service.Tags)}),n=n.filter(function(e){return void 0!==e}),n=n.uniq().join(", "),e.set("content",t),e.set("tags",n)}}),App.NodesShowRoute=App.BaseRoute.extend({model:function(e){var t=this.modelFor("dc").dc,n=App.get("settings.token");return Ember.RSVP.hash({dc:t,token:n,node:Ember.$.getJSON(formatUrl("/v1/internal/ui/node/"+e.name,t,n)).then(function(e){return App.Node.create(e)}),nodes:Ember.$.getJSON(formatUrl("/v1/internal/ui/node/"+e.name,t,n)).then(function(e){return App.Node.create(e)})})},afterModel:function(e){return Ember.$.getJSON(formatUrl("/v1/session/node/"+e.node.Node,e.dc,e.token)).then(function(t){return e.sessions=t,e})},setupController:function(e,t){e.set("content",t.node),e.set("sessions",t.sessions),e.set("nodes",t.nodes)}}),App.NodesRoute=App.BaseRoute.extend({model:function(){var e=this.modelFor("dc").dc,t=App.get("settings.token");return Ember.$.getJSON(formatUrl("/v1/internal/ui/nodes",e,t)).then(function(e){var t=[];return e.map(function(e){t.push(App.Node.create(e))}),t})},setupController:function(e,t){e.set("nodes",t)}}),App.AclsRoute=App.BaseRoute.extend({model:function(){var e=this.modelFor("dc").dc,t=App.get("settings.token");return Ember.$.getJSON(formatUrl("/v1/acl/list",e,t)).then(function(e){var t=[];return e.map(function(e){"anonymous"===e.ID?t.unshift(App.Acl.create(e)):t.push(App.Acl.create(e))}),t})},actions:{error:function(e){return e&&401===e.status?this.transitionTo("dc.aclsdisabled"):e&&403===e.status&&this.transitionTo("dc.unauthorized"),!0}},setupController:function(e,t){e.set("acls",t),e.set("newAcl",App.Acl.create())}}),App.AclsShowRoute=App.BaseRoute.extend({model:function(e){var t=this.modelFor("dc").dc,n=App.get("settings.token");return Ember.RSVP.hash({dc:t,acl:Ember.$.getJSON(formatUrl("/v1/acl/info/"+e.id,t,n)).then(function(e){return App.Acl.create(e[0])})})},setupController:function(e,t){e.set("content",t.acl)}}),App.SettingsRoute=App.BaseRoute.extend({model:function(){return App.get("settings")}});App.ApplicationController=Ember.ObjectController.extend({updateCurrentPath:function(){App.set("currentPath",this.get("currentPath"))}.observes("currentPath")}),App.DcController=Ember.Controller.extend({needs:["application"],isDropdownVisible:!1,datacenter:Ember.computed.alias("content"),totalChecksFailing:function(){return this.get("nodes").reduce(function(e,t){return e+t.get("failingChecks")},0)}.property("nodes"),totalChecksPassing:function(){return this.get("nodes").reduce(function(e,t){return e+t.get("passingChecks")},0)}.property("nodes"),checkMessage:function(){var e=this.get("totalChecksFailing"),t=this.get("totalChecksPassing");return this.get("hasFailingChecks")===!0?e+" failing":t+" passing"}.property("nodes"),checkStatus:function(){return this.get("hasFailingChecks")===!0?"failing":"passing"}.property("nodes"),hasFailingChecks:Ember.computed.gt("totalChecksFailing",0),actions:{toggle:function(){this.toggleProperty("isDropdownVisible")},hideDrop:function(){this.set("isDropdownVisible",!1)}}}),KvBaseController=Ember.ObjectController.extend({getParentKeyRoute:function(){return this.get(this.get("isRoot")?"rootKey":"parentKey")},transitionToNearestParent:function(e){var t=this,n=t.get("rootKey"),s=t.get("dc").get("datacenter"),o=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/kv/"+e+"?keys",s,o),type:"GET"}).then(function(){t.transitionToRoute("kv.show",e)}).fail(function(e){404===e.status&&t.transitionToRoute("kv.show",n)}),t.set("isLoading",!1)}}),App.KvShowController=KvBaseController.extend(Ember.Validations.Mixin,{needs:["dc"],dc:Ember.computed.alias("controllers.dc"),isLoading:!1,actions:{createKey:function(){this.set("isLoading",!0);var e=this,t=e.get("newKey"),n=e.get("parentKey"),s=(e.get("grandParentKey"),e.get("dc").get("datacenter")),o=App.get("settings.token");void 0!==n&&"/"!==n&&t.set("Key",n+t.get("Key")),Ember.$.ajax({url:formatUrl("/v1/kv/"+t.get("Key"),s,o),type:"PUT",data:t.get("Value")}).then(function(){t.get("isFolder")===!0?e.transitionToRoute("kv.show",t.get("Key")):e.transitionToRoute("kv.edit",t.get("Key")),e.set("isLoading",!1)}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText)})},deleteFolder:function(){this.set("isLoading",!0);var e=this,t=e.get("dc").get("datacenter"),n=e.get("grandParentKey"),s=App.get("settings.token");window.confirm("Are you sure you want to delete this folder?")&&Ember.$.ajax({url:formatUrl("/v1/kv/"+e.get("parentKey")+"?recurse",t,s),type:"DELETE"}).then(function(){e.transitionToNearestParent(n)}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText)})}}}),App.KvEditController=KvBaseController.extend({isLoading:!1,needs:["dc"],dc:Ember.computed.alias("controllers.dc"),actions:{updateKey:function(){this.set("isLoading",!0);var e=this.get("dc").get("datacenter"),t=this.get("model"),n=this,s=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/kv/"+t.get("Key"),e,s),type:"PUT",data:t.get("valueDecoded")}).then(function(){n.set("isLoading",!1)}).fail(function(e){n.set("errorMessage","Received error while processing: "+e.statusText)})},cancelEdit:function(){this.set("isLoading",!0),this.transitionToRoute("kv.show",this.getParentKeyRoute()),this.set("isLoading",!1)},deleteKey:function(){this.set("isLoading",!0);var e=this,t=e.get("dc").get("datacenter"),n=e.get("model"),s=e.getParentKeyRoute(),o=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/kv/"+n.get("Key"),t,o),type:"DELETE"}).then(function(){e.transitionToNearestParent(s)}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText)})}}}),ItemBaseController=Ember.ArrayController.extend({needs:["dc","application"],queryParams:["filter","status","condensed"],dc:Ember.computed.alias("controllers.dc"),condensed:!0,hasExpanded:!0,filterText:"Filter by name",filter:"",status:"any status",statuses:["any status","passing","failing"],isShowingItem:function(){var e=this.get("controllers.application.currentPath");return"dc.nodes.show"===e||"dc.services.show"===e}.property("controllers.application.currentPath"),filteredContent:function(){var e=this.get("filter"),t=this.get("status"),n=this.get("items").filter(function(t){return t.get("filterKey").toLowerCase().match(e.toLowerCase())});switch(t){case"passing":return n.filterBy("hasFailingChecks",!1);case"failing":return n.filterBy("hasFailingChecks",!0);default:return n}}.property("filter","status","items.@each"),actions:{toggleCondensed:function(){this.toggleProperty("condensed")}}}),App.NodesShowController=Ember.ObjectController.extend({needs:["dc","nodes"],dc:Ember.computed.alias("controllers.dc"),actions:{deregisterNode:function(){this.set("isLoading",!0);var e=this,t=e.get("model"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");window.confirm("Are you sure you want to deregister this node?")&&Ember.$.ajax({url:formatUrl("/v1/catalog/deregister",n,s),type:"PUT",data:JSON.stringify({Datacenter:n,Node:t.Node})}).then(function(){var n=e.get("controllers.nodes").get("nodes");e.get("controllers.nodes").set("nodes",n.filter(function(e){return e.Node!==t.Node})),e.transitionToRoute("nodes")}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText)})},invalidateSession:function(e){this.set("isLoading",!0);var t=this,n=t.get("model"),s=t.get("dc").get("datacenter"),o=App.get("settings.token");window.confirm("Are you sure you want to invalidate this session?")&&Ember.$.ajax({url:formatUrl("/v1/session/destroy/"+e,s,o),type:"PUT"}).then(function(){return Ember.$.getJSON(formatUrl("/v1/session/node/"+n.Node,s,o)).then(function(e){t.set("sessions",e)})}).fail(function(e){t.set("errorMessage","Received error while processing: "+e.statusText)})}}}),App.NodesController=ItemBaseController.extend({items:Ember.computed.alias("nodes")}),App.ServicesController=ItemBaseController.extend({items:Ember.computed.alias("services")}),App.AclsController=Ember.ArrayController.extend({needs:["dc","application"],queryParams:["filter"],filterText:"Filter by name or ID",searchBar:!0,newAclButton:!0,types:["management","client"],dc:Ember.computed.alias("controllers.dc"),items:Ember.computed.alias("acls"),filter:"",isShowingItem:function(){var e=this.get("controllers.application.currentPath");return"dc.acls.show"===e}.property("controllers.application.currentPath"),filteredContent:function(){var e=this.get("filter"),t=this.get("items").filter(function(t){var n=t.get("Name").toLowerCase().match(e.toLowerCase());return null!==n?n:t.get("ID").toLowerCase().match(e.toLowerCase())});return t}.property("filter","items.@each"),actions:{createAcl:function(){this.set("isLoading",!0);var e=this,t=e.get("newAcl"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/acl/create",n,s),type:"PUT",data:JSON.stringify(t)}).then(function(t){e.transitionToRoute("acls.show",t.ID),Ember.$.getJSON(formatUrl("/v1/acl/list",n,s)).then(function(t){var n=[];t.map(function(e){n.push(App.Acl.create(e))}),e.set("items",n)}),e.set("isLoading",!1)}).fail(function(t){notify("Received error while creating ACL: "+t.statusText,8e3),e.set("isLoading",!1)})}}}),App.AclsShowController=Ember.ObjectController.extend({needs:["dc","acls"],dc:Ember.computed.alias("controllers.dc"),isLoading:!1,types:["management","client"],actions:{set:function(){this.set("isLoading",!0);{var e=this,t=e.get("model");e.get("dc").get("datacenter")}if(window.confirm("Are you sure you want to use this token for your session?")){{App.set("settings.token",t.ID)}e.transitionToRoute("services"),this.set("isLoading",!1),notify("Now using token: "+t.ID,3e3)}},clone:function(){this.set("isLoading",!0);var e=this,t=e.get("model"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");e.transitionToRoute("services"),Ember.$.ajax({url:formatUrl("/v1/acl/clone/"+t.ID,n,s),type:"PUT"}).then(function(t){e.transitionToRoute("acls.show",t.ID),e.set("isLoading",!1),notify("Successfully cloned token",4e3)}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText),e.set("isLoading",!1)})},"delete":function(){this.set("isLoading",!0);var e=this,t=e.get("model"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");window.confirm("Are you sure you want to delete this token?")&&Ember.$.ajax({url:formatUrl("/v1/acl/destroy/"+t.ID,n,s),type:"PUT"}).then(function(){Ember.$.getJSON(formatUrl("/v1/acl/list",n,s)).then(function(t){objs=[],t.map(function(e){"anonymous"===e.ID?objs.unshift(App.Acl.create(e)):objs.push(App.Acl.create(e))}),e.get("controllers.acls").set("acls",objs)}).then(function(){e.transitionToRoute("acls"),e.set("isLoading",!1),notify("ACL deleted successfully",3e3)})}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText),e.set("isLoading",!1)})},updateAcl:function(){this.set("isLoading",!0);var e=this,t=e.get("model"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/acl/update",n,s),type:"PUT",data:JSON.stringify(t)}).then(function(){e.set("isLoading",!1),notify("ACL updated successfully",3e3)}).fail(function(t){notify("Received error while updating ACL: "+t.statusText,8e3),e.set("isLoading",!1)})}}}),App.SettingsController=Ember.ObjectController.extend({actions:{reset:function(){this.set("isLoading",!0);var e=this;window.confirm("Are your sure you want to reset your settings?")&&(localStorage.clear(),e.set("content",App.Settings.create()),App.set("settings.token",""),notify("Settings reset",3e3),this.set("isLoading",!1))}}});App.DcView=Ember.View.extend({templateName:"dc",classNames:"dropdowns",click:function(e){$(e.target).is(".dropdowns")&&$("ul.dropdown-menu").hide()}}),App.ItemView=Ember.View.extend({templateName:"item"}),App.ServicesView=Ember.View.extend({templateName:"services"}),App.ServicesShowView=Ember.View.extend({templateName:"service"}),App.ServicesLoadingView=Ember.View.extend({templateName:"item/loading"}),App.NodesView=Ember.View.extend({templateName:"nodes"}),App.NodesShowView=Ember.View.extend({templateName:"node"}),App.NodesLoadingView=Ember.View.extend({templateName:"item/loading"}),App.KvListView=Ember.View.extend({templateName:"kv"}),App.ActionBarView=Ember.View.extend({templateName:"actionbar"}),App.AclView=Ember.View.extend({templateName:"acls"}),App.AclsShowView=Ember.View.extend({templateName:"acl"}),App.SettingsView=Ember.View.extend({templateName:"settings"});function notify(e,a){void 0!==window.notifications&&window.notifications.length>0&&$(window.notifications).each(function(e,a){a.dismiss()});var n=new NotificationFx({message:"

"+e+"

",layout:"growl",effect:"slide",type:"notice",ttl:a});n.show(),window.notifications=[],window.notifications.push(n)}Ember.Handlebars.helper("panelBar",function(e){var a;return a="passing"==e?"bg-green":"bg-orange",new Handlebars.SafeString('
')}),Ember.Handlebars.helper("listBar",function(e){var a;return a="passing"==e?"bg-green":"bg-orange",new Handlebars.SafeString('
')}),Ember.Handlebars.helper("sessionName",function(e){var a;return a=""===e.Name?""+e.ID+"":""+e.Name+" "+e.ID+"",new Handlebars.SafeString(a)}),Ember.Handlebars.helper("sessionMeta",function(e){var a='";return""!==e.TTL&&(a=a+'"),new Handlebars.SafeString(a)}),Ember.Handlebars.helper("aclName",function(e,a){return""===e?a:new Handlebars.SafeString(e+' '+a+"")}),Ember.Handlebars.helper("formatRules",function(e){return""===e?"No rules defined":e}),Ember.Handlebars.helper("serviceTagMessage",function(e){return null===e?"No tags":void 0}); \ No newline at end of file +window.App=Ember.Application.create({rootElement:"#app",currentPath:""}),Ember.Application.initializer({name:"settings",initialize:function(t,e){e.set("settings",App.Settings.create()),void 0===App.get("settings.token")&&App.set("settings.token","")}}),App.Router.map(function(){this.resource("dc",{path:"/:dc"},function(){this.resource("services",{path:"/services"},function(){this.route("show",{path:"/*name"})}),this.resource("nodes",{path:"/nodes"},function(){this.route("show",{path:"/:name"})}),this.resource("kv",{path:"/kv"},function(){this.route("index",{path:"/"}),this.route("show",{path:"/*key"}),this.route("edit",{path:"/*key/edit"})}),this.resource("acls",{path:"/acls"},function(){this.route("show",{path:"/:id"})}),this.route("aclsdisabled",{path:"/aclsdisabled"}),this.route("unauthorized",{path:"/unauthorized"}),this.resource("settings",{path:"/settings"})}),this.route("index",{path:"/"})});App.Service=Ember.Object.extend({failingChecks:function(){if(void 0!==this.get("ChecksCritical"))return this.get("ChecksCritical")+this.get("ChecksWarning");var e=this.get("Checks");return e.filterBy("Status","critical").get("length")+e.filterBy("Status","warning").get("length")}.property("Checks"),passingChecks:function(){return void 0!==this.get("ChecksPassing")?this.get("ChecksPassing"):this.get("Checks").filterBy("Status","passing").get("length")}.property("Checks"),checkMessage:function(){return this.get("hasFailingChecks")===!1?this.get("passingChecks")+" passing":this.get("failingChecks")+" failing"}.property("Checks"),nodes:function(){return this.get("Nodes")}.property("Nodes"),hasFailingChecks:Ember.computed.gt("failingChecks",0),filterKey:Ember.computed.alias("Name")}),App.Node=Ember.Object.extend({failingChecks:function(){return this.get("Checks").reduce(function(e,t){var r=Ember.get(t,"Status");return"critical"===r||"warning"===r?e+1:e},0)}.property("Checks"),passingChecks:function(){return this.get("Checks").filterBy("Status","passing").get("length")}.property("Checks"),checkMessage:function(){return this.get("hasFailingChecks")===!1?this.get("passingChecks")+" passing":this.get("failingChecks")+" failing"}.property("Checks"),hasFailingChecks:Ember.computed.gt("failingChecks",0),numServices:Ember.computed.alias("Services.length"),services:Ember.computed.alias("Services"),filterKey:Ember.computed.alias("Node")}),App.Key=Ember.Object.extend(Ember.Validations.Mixin,{validations:{Key:{presence:!0}},keyValid:Ember.computed.empty("errors.Key"),valueValid:Ember.computed.empty("errors.Value"),keyWithoutParent:function(){return this.get("Key").replace(this.get("parentKey"),"")}.property("Key"),isFolder:function(){return void 0===this.get("Key")?!1:"/"===this.get("Key").slice(-1)}.property("Key"),isLocked:function(){return this.get("Session")?!0:!1}.property("Session"),linkToRoute:function(){return"/"===this.get("Key").slice(-1)?"kv.show":"kv.edit"}.property("Key"),valueDecoded:function(e,t){return arguments.length>1?(this.set("Value",t),t):null===this.get("Value")?"":(Base64.extendString&&Base64.extendString(),this.get("Value").fromBase64())}.property("Value"),keyParts:function(){var e=this.get("Key");return"/"==e.slice(-1)&&(e=e.substring(0,e.length-1)),e.split("/")}.property("Key"),parentKey:function(){var e=this.get("keyParts").toArray();return e.pop(),e.join("/")+"/"}.property("Key"),grandParentKey:function(){var e=this.get("keyParts").toArray();return e.pop(),e.pop(),e.join("/")+"/"}.property("Key")}),App.Acl=Ember.Object.extend({isNotAnon:function(){return"anonymous"===this.get("ID")?!1:!0}.property("ID")}),App.Settings=Ember.Object.extend({unknownProperty:function(e){return localStorage[e]},setUnknownProperty:function(e,t){return Ember.isNone(t)?delete localStorage[e]:localStorage[e]=t,this.notifyPropertyChange(e),t},clear:function(){this.beginPropertyChanges();for(var e=0,t=localStorage.length;t>e;e++)this.set(localStorage.key(e));localStorage.clear(),this.endPropertyChanges()}});function formatUrl(e,t,n){return null==n&&(n=""),e.indexOf("?")>0?(e=e+"&dc="+t,e=e+"&token="+n):(e=e+"?dc="+t,e=e+"&token="+n),e}App.BaseRoute=Ember.Route.extend({rootKey:"",condensedView:!1,queryParams:{filter:{replace:!0}},getParentAndGrandparent:function(e){var t=this.rootKey,n=this.rootKey,o=e.split("/");return o.length>0&&(o.pop(),t=o.join("/")+"/"),o.length>1&&(o.pop(),n=o.join("/")+"/"),{parent:t,grandParent:n,isRoot:"/"===t}},removeDuplicateKeys:function(e,t){return e.forEach(function(n,o){n.get("Key")==t&&e.splice(o,1)}),e},actions:{linkToKey:function(e){"/"==e?this.transitionTo("kv.show",""):"/"===e.slice(-1)||e===this.rootKey?this.transitionTo("kv.show",e):this.transitionTo("kv.edit",e)}}}),App.IndexRoute=App.BaseRoute.extend({model:function(){return Ember.$.getJSON("/v1/catalog/datacenters").then(function(e){return e})},afterModel:function(e){1===e.get("length")&&this.transitionTo("services",e[0])}}),App.DcRoute=App.BaseRoute.extend({model:function(e){var t=App.get("settings.token");return Ember.RSVP.hash({dc:e.dc,dcs:Ember.$.getJSON("/v1/catalog/datacenters"),nodes:Ember.$.getJSON(formatUrl("/v1/internal/ui/nodes",e.dc,t)).then(function(e){var t=[];return e.map(function(e){t.push(App.Node.create(e))}),t})})},setupController:function(e,t){e.set("content",t.dc),e.set("nodes",t.nodes),e.set("dcs",t.dcs),e.set("isDropdownVisible",!1)}}),App.KvIndexRoute=App.BaseRoute.extend({beforeModel:function(){this.transitionTo("kv.show",this.rootKey)}}),App.KvShowRoute=App.BaseRoute.extend({model:function(e){var t=e.key,n=this.modelFor("dc").dc,o=App.get("settings.token");return Ember.RSVP.hash({key:t,keys:Ember.$.getJSON(formatUrl("/v1/kv/"+t+"?keys&seperator=/",n,o)).then(function(e){var t=[];return e.map(function(e){t.push(App.Key.create({Key:e}))}),t})})},setupController:function(e,t){var n=t.key,o=this.getParentAndGrandparent(n);t.keys=this.removeDuplicateKeys(t.keys,t.key),e.set("content",t.keys),e.set("parentKey",o.parent),e.set("grandParentKey",o.grandParent),e.set("isRoot",o.isRoot),e.set("newKey",App.Key.create()),e.set("rootKey",this.rootKey)}}),App.KvEditRoute=App.BaseRoute.extend({model:function(e){var t=e.key,n=this.modelFor("dc").dc,o=this.getParentAndGrandparent(t),r=App.get("settings.token");return Ember.RSVP.hash({dc:n,token:r,key:Ember.$.getJSON(formatUrl("/v1/kv/"+t,n,r)).then(function(e){return App.Key.create().setProperties(e[0])}),keys:keysPromise=Ember.$.getJSON(formatUrl("/v1/kv/"+o.parent+"?keys&seperator=/",n,r)).then(function(e){var t=[];return e.map(function(e){t.push(App.Key.create({Key:e}))}),t})})},afterModel:function(e){return e.key.get("isLocked")?Ember.$.getJSON(formatUrl("/v1/session/info/"+e.key.Session,e.dc,e.token)).then(function(t){return e.session=t[0],e}):e},setupController:function(e,t){var n=t.key,o=this.getParentAndGrandparent(n.get("Key"));t.keys=this.removeDuplicateKeys(t.keys,o.parent),e.set("content",t.key),e.set("parentKey",o.parent),e.set("grandParentKey",o.grandParent),e.set("isRoot",o.isRoot),e.set("siblings",t.keys),e.set("rootKey",this.rootKey),e.set("session",t.session)}}),App.ServicesRoute=App.BaseRoute.extend({model:function(){var e=this.modelFor("dc").dc,t=App.get("settings.token");return Ember.$.getJSON(formatUrl("/v1/internal/ui/services",e,t)).then(function(e){var t=[];return e.map(function(e){t.push(App.Service.create(e))}),t})},setupController:function(e,t){e.set("services",t)}}),App.ServicesShowRoute=App.BaseRoute.extend({model:function(e){var t=this.modelFor("dc").dc,n=App.get("settings.token");return Ember.$.getJSON(formatUrl("/v1/health/service/"+e.name,t,n)).then(function(e){var t=[];return e.map(function(e){t.push(App.Node.create(e))}),t})},setupController:function(e,t){var n=[];t.map(function(e){n=n.concat(e.Service.Tags)}),n=n.filter(function(e){return void 0!==e}),n=n.uniq().join(", "),e.set("content",t),e.set("tags",n)}}),App.NodesShowRoute=App.BaseRoute.extend({model:function(e){var t=this.modelFor("dc").dc,n=App.get("settings.token");return Ember.RSVP.hash({dc:t,token:n,node:Ember.$.getJSON(formatUrl("/v1/internal/ui/node/"+e.name,t,n)).then(function(e){return App.Node.create(e)}),nodes:Ember.$.getJSON(formatUrl("/v1/internal/ui/node/"+e.name,t,n)).then(function(e){return App.Node.create(e)})})},afterModel:function(e){return Ember.$.getJSON(formatUrl("/v1/session/node/"+e.node.Node,e.dc,e.token)).then(function(t){return e.sessions=t,e})},setupController:function(e,t){e.set("content",t.node),e.set("sessions",t.sessions),e.set("nodes",t.nodes)}}),App.NodesRoute=App.BaseRoute.extend({model:function(){var e=this.modelFor("dc").dc,t=App.get("settings.token");return Ember.$.getJSON(formatUrl("/v1/internal/ui/nodes",e,t)).then(function(e){var t=[];return e.map(function(e){t.push(App.Node.create(e))}),t})},setupController:function(e,t){e.set("nodes",t)}}),App.AclsRoute=App.BaseRoute.extend({model:function(){var e=this.modelFor("dc").dc,t=App.get("settings.token");return Ember.$.getJSON(formatUrl("/v1/acl/list",e,t)).then(function(e){var t=[];return e.map(function(e){"anonymous"===e.ID?t.unshift(App.Acl.create(e)):t.push(App.Acl.create(e))}),t})},actions:{error:function(e){return e&&401===e.status?this.transitionTo("dc.aclsdisabled"):e&&403===e.status&&this.transitionTo("dc.unauthorized"),!0}},setupController:function(e,t){e.set("acls",t),e.set("newAcl",App.Acl.create())}}),App.AclsShowRoute=App.BaseRoute.extend({model:function(e){var t=this.modelFor("dc").dc,n=App.get("settings.token");return Ember.RSVP.hash({dc:t,acl:Ember.$.getJSON(formatUrl("/v1/acl/info/"+e.id,t,n)).then(function(e){return App.Acl.create(e[0])})})},setupController:function(e,t){e.set("content",t.acl)}}),App.SettingsRoute=App.BaseRoute.extend({model:function(){return App.get("settings")}});App.ApplicationController=Ember.ObjectController.extend({updateCurrentPath:function(){App.set("currentPath",this.get("currentPath"))}.observes("currentPath")}),App.DcController=Ember.Controller.extend({needs:["application"],isDropdownVisible:!1,datacenter:Ember.computed.alias("content"),totalChecksFailing:function(){return this.get("nodes").reduce(function(e,t){return e+t.get("failingChecks")},0)}.property("nodes"),totalChecksPassing:function(){return this.get("nodes").reduce(function(e,t){return e+t.get("passingChecks")},0)}.property("nodes"),checkMessage:function(){var e=this.get("totalChecksFailing"),t=this.get("totalChecksPassing");return this.get("hasFailingChecks")===!0?e+" failing":t+" passing"}.property("nodes"),checkStatus:function(){return this.get("hasFailingChecks")===!0?"failing":"passing"}.property("nodes"),hasFailingChecks:Ember.computed.gt("totalChecksFailing",0),actions:{toggle:function(){this.toggleProperty("isDropdownVisible")},hideDrop:function(){this.set("isDropdownVisible",!1)}}}),KvBaseController=Ember.ObjectController.extend({getParentKeyRoute:function(){return this.get(this.get("isRoot")?"rootKey":"parentKey")},transitionToNearestParent:function(e){var t=this,n=t.get("rootKey"),s=t.get("dc").get("datacenter"),o=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/kv/"+e+"?keys",s,o),type:"GET"}).then(function(){t.transitionToRoute("kv.show",e)}).fail(function(e){404===e.status&&t.transitionToRoute("kv.show",n)}),t.set("isLoading",!1)}}),App.KvShowController=KvBaseController.extend(Ember.Validations.Mixin,{needs:["dc"],dc:Ember.computed.alias("controllers.dc"),isLoading:!1,actions:{createKey:function(){this.set("isLoading",!0);var e=this,t=e.get("newKey"),n=e.get("parentKey"),s=(e.get("grandParentKey"),e.get("dc").get("datacenter")),o=App.get("settings.token");void 0!==n&&"/"!==n&&t.set("Key",n+t.get("Key")),Ember.$.ajax({url:formatUrl("/v1/kv/"+t.get("Key"),s,o),type:"PUT",data:t.get("Value")}).then(function(){t.get("isFolder")===!0?e.transitionToRoute("kv.show",t.get("Key")):e.transitionToRoute("kv.edit",t.get("Key")),e.set("isLoading",!1)}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText)})},deleteFolder:function(){this.set("isLoading",!0);var e=this,t=e.get("dc").get("datacenter"),n=e.get("grandParentKey"),s=App.get("settings.token");window.confirm("Are you sure you want to delete this folder?")&&Ember.$.ajax({url:formatUrl("/v1/kv/"+e.get("parentKey")+"?recurse",t,s),type:"DELETE"}).then(function(){e.transitionToNearestParent(n)}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText)})}}}),App.KvEditController=KvBaseController.extend({isLoading:!1,needs:["dc"],dc:Ember.computed.alias("controllers.dc"),actions:{updateKey:function(){this.set("isLoading",!0);var e=this.get("dc").get("datacenter"),t=this.get("model"),n=this,s=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/kv/"+t.get("Key"),e,s),type:"PUT",data:t.get("valueDecoded")}).then(function(){n.set("isLoading",!1)}).fail(function(e){n.set("errorMessage","Received error while processing: "+e.statusText)})},cancelEdit:function(){this.set("isLoading",!0),this.transitionToRoute("kv.show",this.getParentKeyRoute()),this.set("isLoading",!1)},deleteKey:function(){this.set("isLoading",!0);var e=this,t=e.get("dc").get("datacenter"),n=e.get("model"),s=e.getParentKeyRoute(),o=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/kv/"+n.get("Key"),t,o),type:"DELETE"}).then(function(){e.transitionToNearestParent(s)}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText)})}}}),ItemBaseController=Ember.ArrayController.extend({needs:["dc","application"],queryParams:["filter","status","condensed"],dc:Ember.computed.alias("controllers.dc"),condensed:!0,hasExpanded:!0,filterText:"Filter by name",filter:"",status:"any status",statuses:["any status","passing","failing"],isShowingItem:function(){var e=this.get("controllers.application.currentPath");return"dc.nodes.show"===e||"dc.services.show"===e}.property("controllers.application.currentPath"),filteredContent:function(){var e=this.get("filter"),t=this.get("status"),n=this.get("items").filter(function(t){return t.get("filterKey").toLowerCase().match(e.toLowerCase())});switch(t){case"passing":return n.filterBy("hasFailingChecks",!1);case"failing":return n.filterBy("hasFailingChecks",!0);default:return n}}.property("filter","status","items.@each"),actions:{toggleCondensed:function(){this.toggleProperty("condensed")}}}),App.NodesShowController=Ember.ObjectController.extend({needs:["dc","nodes"],dc:Ember.computed.alias("controllers.dc"),actions:{deregisterNode:function(){this.set("isLoading",!0);var e=this,t=e.get("model"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");window.confirm("Are you sure you want to deregister this node?")&&Ember.$.ajax({url:formatUrl("/v1/catalog/deregister",n,s),type:"PUT",data:JSON.stringify({Datacenter:n,Node:t.Node})}).then(function(){var n=e.get("controllers.nodes").get("nodes");e.get("controllers.nodes").set("nodes",n.filter(function(e){return e.Node!==t.Node})),e.transitionToRoute("nodes")}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText)})},invalidateSession:function(e){this.set("isLoading",!0);var t=this,n=t.get("model"),s=t.get("dc").get("datacenter"),o=App.get("settings.token");window.confirm("Are you sure you want to invalidate this session?")&&Ember.$.ajax({url:formatUrl("/v1/session/destroy/"+e,s,o),type:"PUT"}).then(function(){return Ember.$.getJSON(formatUrl("/v1/session/node/"+n.Node,s,o)).then(function(e){t.set("sessions",e)})}).fail(function(e){t.set("errorMessage","Received error while processing: "+e.statusText)})}}}),App.NodesController=ItemBaseController.extend({items:Ember.computed.alias("nodes")}),App.ServicesController=ItemBaseController.extend({items:Ember.computed.alias("services")}),App.AclsController=Ember.ArrayController.extend({needs:["dc","application"],queryParams:["filter"],filterText:"Filter by name or ID",searchBar:!0,newAclButton:!0,types:["management","client"],dc:Ember.computed.alias("controllers.dc"),items:Ember.computed.alias("acls"),filter:"",isShowingItem:function(){var e=this.get("controllers.application.currentPath");return"dc.acls.show"===e}.property("controllers.application.currentPath"),filteredContent:function(){var e=this.get("filter"),t=this.get("items").filter(function(t){var n=t.get("Name").toLowerCase().match(e.toLowerCase());return null!==n?n:t.get("ID").toLowerCase().match(e.toLowerCase())});return t}.property("filter","items.@each"),actions:{createAcl:function(){this.set("isLoading",!0);var e=this,t=e.get("newAcl"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/acl/create",n,s),type:"PUT",data:JSON.stringify(t)}).then(function(t){e.transitionToRoute("acls.show",t.ID),Ember.$.getJSON(formatUrl("/v1/acl/list",n,s)).then(function(t){var n=[];t.map(function(e){n.push(App.Acl.create(e))}),e.set("items",n)}),e.set("isLoading",!1)}).fail(function(t){notify("Received error while creating ACL: "+t.statusText,8e3),e.set("isLoading",!1)})}}}),App.AclsShowController=Ember.ObjectController.extend({needs:["dc","acls"],dc:Ember.computed.alias("controllers.dc"),isLoading:!1,types:["management","client"],actions:{set:function(){this.set("isLoading",!0);{var e=this,t=e.get("model");e.get("dc").get("datacenter")}if(window.confirm("Are you sure you want to use this token for your session?")){{App.set("settings.token",t.ID)}e.transitionToRoute("services"),this.set("isLoading",!1),notify("Now using token: "+t.ID,3e3)}},clone:function(){this.set("isLoading",!0);var e=this,t=e.get("model"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");e.transitionToRoute("services"),Ember.$.ajax({url:formatUrl("/v1/acl/clone/"+t.ID,n,s),type:"PUT"}).then(function(t){e.transitionToRoute("acls.show",t.ID),e.set("isLoading",!1),notify("Successfully cloned token",4e3)}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText),e.set("isLoading",!1)})},"delete":function(){this.set("isLoading",!0);var e=this,t=e.get("model"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");window.confirm("Are you sure you want to delete this token?")&&Ember.$.ajax({url:formatUrl("/v1/acl/destroy/"+t.ID,n,s),type:"PUT"}).then(function(){Ember.$.getJSON(formatUrl("/v1/acl/list",n,s)).then(function(t){objs=[],t.map(function(e){"anonymous"===e.ID?objs.unshift(App.Acl.create(e)):objs.push(App.Acl.create(e))}),e.get("controllers.acls").set("acls",objs)}).then(function(){e.transitionToRoute("acls"),e.set("isLoading",!1),notify("ACL deleted successfully",3e3)})}).fail(function(t){e.set("errorMessage","Received error while processing: "+t.statusText),e.set("isLoading",!1)})},updateAcl:function(){this.set("isLoading",!0);var e=this,t=e.get("model"),n=e.get("dc").get("datacenter"),s=App.get("settings.token");Ember.$.ajax({url:formatUrl("/v1/acl/update",n,s),type:"PUT",data:JSON.stringify(t)}).then(function(){e.set("isLoading",!1),notify("ACL updated successfully",3e3)}).fail(function(t){notify("Received error while updating ACL: "+t.statusText,8e3),e.set("isLoading",!1)})}}}),App.SettingsController=Ember.ObjectController.extend({actions:{reset:function(){this.set("isLoading",!0);var e=this;window.confirm("Are your sure you want to reset your settings?")&&(localStorage.clear(),e.set("content",App.Settings.create()),App.set("settings.token",""),notify("Settings reset",3e3),this.set("isLoading",!1))}}});App.DcView=Ember.View.extend({templateName:"dc",classNames:"dropdowns",click:function(e){$(e.target).is(".dropdowns")&&$("ul.dropdown-menu").hide()}}),App.ItemView=Ember.View.extend({templateName:"item"}),App.ServicesView=Ember.View.extend({templateName:"services"}),App.ServicesShowView=Ember.View.extend({templateName:"service"}),App.ServicesLoadingView=Ember.View.extend({templateName:"item/loading"}),App.NodesView=Ember.View.extend({templateName:"nodes"}),App.NodesShowView=Ember.View.extend({templateName:"node"}),App.NodesLoadingView=Ember.View.extend({templateName:"item/loading"}),App.KvListView=Ember.View.extend({templateName:"kv"}),App.ActionBarView=Ember.View.extend({templateName:"actionbar"}),App.AclView=Ember.View.extend({templateName:"acls"}),App.AclsShowView=Ember.View.extend({templateName:"acl"}),App.SettingsView=Ember.View.extend({templateName:"settings"});function notify(e,a){void 0!==window.notifications&&window.notifications.length>0&&$(window.notifications).each(function(e,a){a.dismiss()});var n=new NotificationFx({message:"

"+e+"

",layout:"growl",effect:"slide",type:"notice",ttl:a});n.show(),window.notifications=[],window.notifications.push(n)}Ember.Handlebars.helper("panelBar",function(e){var a;return a="passing"==e?"bg-green":"bg-orange",new Handlebars.SafeString('
')}),Ember.Handlebars.helper("listBar",function(e){var a;return a="passing"==e?"bg-green":"bg-orange",new Handlebars.SafeString('
')}),Ember.Handlebars.helper("sessionName",function(e){var a;return a=""===e.Name?""+e.ID+"":""+e.Name+" "+e.ID+"",new Handlebars.SafeString(a)}),Ember.Handlebars.helper("sessionMeta",function(e){var a='";return""!==e.TTL&&(a=a+'"),new Handlebars.SafeString(a)}),Ember.Handlebars.helper("aclName",function(e,a){return""===e?a:new Handlebars.SafeString(e+' '+a+"")}),Ember.Handlebars.helper("formatRules",function(e){return""===e?"No rules defined":e}),Ember.Handlebars.helper("serviceTagMessage",function(e){return null===e?"No tags":void 0}); diff --git a/src/test/resources/consul_ui/static/base.css b/src/test/resources/consul_ui/static/base.css index 1598f156..dbb2ffe5 100644 --- a/src/test/resources/consul_ui/static/base.css +++ b/src/test/resources/consul_ui/static/base.css @@ -1,1004 +1,1354 @@ body { - -webkit-font-smoothing: antialiased; - font-size: 16px; - color: #555; } + -webkit-font-smoothing: antialiased; + font-size: 16px; + color: #555; +} a { - color: #9e84c5; - font-weight: 600; - -webkit-transition: color 0.2s ease-in-out; - -moz-transition: color 0.2s ease-in-out; - -ms-transition: color 0.2s ease-in-out; - -o-transition: color 0.2s ease-in-out; - transition: color 0.2s ease-in-out; } - a:hover { - text-decoration: none; - color: #8262b4; } - a.subtle { - color: inherit; } - a.subtle:hover { - color: #9e84c5; } + color: #9e84c5; + font-weight: 600; + -webkit-transition: color 0.2s ease-in-out; + -moz-transition: color 0.2s ease-in-out; + -ms-transition: color 0.2s ease-in-out; + -o-transition: color 0.2s ease-in-out; + transition: color 0.2s ease-in-out; +} + +a:hover { + text-decoration: none; + color: #8262b4; +} + +a.subtle { + color: inherit; +} + +a.subtle:hover { + color: #9e84c5; +} code { - color: #69499a; - background-color: #E6E6E6; } + color: #69499a; + background-color: #E6E6E6; +} .help-block { - font-size: 14px; - color: #939393; } + font-size: 14px; + color: #939393; +} small { - color: #777; } + color: #777; +} h1, h2, h3, h4, h5 { - color: #555; } + color: #555; +} h5 { - text-transform: uppercase; - font-weight: 700; - color: #939393; } + text-transform: uppercase; + font-weight: 700; + color: #939393; +} h4.breadcrumbs { - padding-bottom: 5px; - text-transform: uppercase; } - h4.breadcrumbs a { - color: #939393; } + padding-bottom: 5px; + text-transform: uppercase; +} + +h4.breadcrumbs a { + color: #939393; +} pre { - background-color: #777; - color: white; - font-weight: 700; - font-size: 12px; } + background-color: #777; + color: white; + font-weight: 700; + font-size: 12px; +} .bold { - font-weight: 700; } + font-weight: 700; +} .light { - color: #777; } + color: #777; +} .panel { - border-width: 2px; - border-color: #E6E6E6; - -webkit-transition: background-color 0.3s ease-in-out; - -moz-transition: background-color 0.3s ease-in-out; - -ms-transition: background-color 0.3s ease-in-out; - -o-transition: background-color 0.3s ease-in-out; - transition: background-color 0.3s ease-in-out; } - .panel .panel-heading { - padding: 10px 7px; - background-color: transparent; - border-width: 2px; - border-color: #E6E6E6; } - .panel h4.panel-title { - padding: 4px 10px 4px 2px; - font-size: 20px; - color: #939393; - color: #555; - border-radius: 3px; - opacity: 0.8; } - .panel h4.panel-title small { - font-size: 14px; - text-transform: uppercase; - font-weight: 700; - margin-left: 5px; - padding-top: 2px; } - .panel h4.panel-title .no-case { - text-transform: none; } - .panel h4.panel-title .panel-note { - margin-top: 5px; - float: right; - font-weight: 600; - color: #939393; - font-size: 14px; } - .panel h3.panel-title { - padding: 4px 0px 4px 0px; - font-size: 20px; - color: #939393; - color: #555; - border-radius: 3px; } - .panel h3.panel-title small { - font-size: 14px; - margin-left: 5px; } - .panel h3.panel-title .panel-note { - margin-top: 5px; - float: right; - font-weight: 600; - color: #939393; - font-size: 14px; } - .panel .panel-body { - padding: 0px 7px 0px 7px; } - .panel .panel-body p { - font-size: 14px; - color: #555; } - .panel .panel-body h5 { - font-size: 12px; } - .panel .panel-body h4.check { - font-size: 16px; } - .panel .panel-body.panel-form { - padding-bottom: 15px; } - .panel .panel-bar { - width: 100%; - height: 20px; - -webkit-transition: background-color 0.1s linear; - -moz-transition: background-color 0.1s linear; - -ms-transition: background-color 0.1s linear; - -o-transition: background-color 0.1s linear; - transition: background-color 0.1s linear; } - .panel.panel-link { - border-bottom-width: 2px; } - .panel.panel-list ul { - margin: 0; } - .panel.panel-list ul li { - margin: 0; - border: 0; } - .panel .panel-bar-horizontal { - width: 20px; - float: left; - height: 50px; - margin-right: 10px; - display: block; } - .panel.panel-short { - border-bottom-width: 0px; } - .panel.panel-link:hover { - cursor: pointer; - background-color: #fafafa; } - .panel.active { - -webkit-transition: border-color 0.1s linear; - -moz-transition: border-color 0.1s linear; - -ms-transition: border-color 0.1s linear; - -o-transition: border-color 0.1s linear; - transition: border-color 0.1s linear; - border-color: #9e84c5; } - .panel.active > .panel-heading { - border-color: #9e84c5; } - .panel.active .panel-bar { - -webkit-transition: background-color 0.1s linear; - -moz-transition: background-color 0.1s linear; - -ms-transition: background-color 0.1s linear; - -o-transition: background-color 0.1s linear; - transition: background-color 0.1s linear; - background-color: #9e84c5; } + border-width: 2px; + border-color: #E6E6E6; + -webkit-transition: background-color 0.3s ease-in-out; + -moz-transition: background-color 0.3s ease-in-out; + -ms-transition: background-color 0.3s ease-in-out; + -o-transition: background-color 0.3s ease-in-out; + transition: background-color 0.3s ease-in-out; +} + +.panel .panel-heading { + padding: 10px 7px; + background-color: transparent; + border-width: 2px; + border-color: #E6E6E6; +} + +.panel h4.panel-title { + padding: 4px 10px 4px 2px; + font-size: 20px; + color: #939393; + color: #555; + border-radius: 3px; + opacity: 0.8; +} + +.panel h4.panel-title small { + font-size: 14px; + text-transform: uppercase; + font-weight: 700; + margin-left: 5px; + padding-top: 2px; +} + +.panel h4.panel-title .no-case { + text-transform: none; +} + +.panel h4.panel-title .panel-note { + margin-top: 5px; + float: right; + font-weight: 600; + color: #939393; + font-size: 14px; +} + +.panel h3.panel-title { + padding: 4px 0px 4px 0px; + font-size: 20px; + color: #939393; + color: #555; + border-radius: 3px; +} + +.panel h3.panel-title small { + font-size: 14px; + margin-left: 5px; +} + +.panel h3.panel-title .panel-note { + margin-top: 5px; + float: right; + font-weight: 600; + color: #939393; + font-size: 14px; +} + +.panel .panel-body { + padding: 0px 7px 0px 7px; +} + +.panel .panel-body p { + font-size: 14px; + color: #555; +} + +.panel .panel-body h5 { + font-size: 12px; +} + +.panel .panel-body h4.check { + font-size: 16px; +} + +.panel .panel-body.panel-form { + padding-bottom: 15px; +} + +.panel .panel-bar { + width: 100%; + height: 20px; + -webkit-transition: background-color 0.1s linear; + -moz-transition: background-color 0.1s linear; + -ms-transition: background-color 0.1s linear; + -o-transition: background-color 0.1s linear; + transition: background-color 0.1s linear; +} + +.panel.panel-link { + border-bottom-width: 2px; +} + +.panel.panel-list ul { + margin: 0; +} + +.panel.panel-list ul li { + margin: 0; + border: 0; +} + +.panel .panel-bar-horizontal { + width: 20px; + float: left; + height: 50px; + margin-right: 10px; + display: block; +} + +.panel.panel-short { + border-bottom-width: 0px; +} + +.panel.panel-link:hover { + cursor: pointer; + background-color: #fafafa; +} + +.panel.active { + -webkit-transition: border-color 0.1s linear; + -moz-transition: border-color 0.1s linear; + -ms-transition: border-color 0.1s linear; + -o-transition: border-color 0.1s linear; + transition: border-color 0.1s linear; + border-color: #9e84c5; +} + +.panel.active > .panel-heading { + border-color: #9e84c5; +} + +.panel.active .panel-bar { + -webkit-transition: background-color 0.1s linear; + -moz-transition: background-color 0.1s linear; + -ms-transition: background-color 0.1s linear; + -o-transition: background-color 0.1s linear; + transition: background-color 0.1s linear; + background-color: #9e84c5; +} .top-brand { - margin-top: 20px; - background: transparent url("consul-logo.png") 0 no-repeat; - background-size: 30px 30px; - width: 30px; - height: 30px; } + margin-top: 20px; + background: transparent url("consul-logo.png") 0 no-repeat; + background-size: 30px 30px; + width: 30px; + height: 30px; +} .topbar { - padding: 30px; - padding-top: 10px; - padding-bottom: 10px; - margin-bottom: 20px; - min-height: 95px; - border-bottom: 1px #eee solid; } - .topbar .btn { - margin-top: 20px; - min-width: 100px; } - .topbar .btn-dropdown { - width: auto; } - .topbar ul.dropdown-menu li a { - text-transform: uppercase; - font-weight: 600; - font-size: 12px; - color: #777; - -webkit-transition: background-color 0.1s ease-in-out; - -moz-transition: background-color 0.1s ease-in-out; - -ms-transition: background-color 0.1s ease-in-out; - -o-transition: background-color 0.1s ease-in-out; - transition: background-color 0.1s ease-in-out; } - .topbar ul.dropdown-menu li a:hover { - color: #5e5e5e; - background-color: #f3f3f3; } + padding: 30px; + padding-top: 10px; + padding-bottom: 10px; + margin-bottom: 20px; + min-height: 95px; + border-bottom: 1px #eee solid; +} + +.topbar .btn { + margin-top: 20px; + min-width: 100px; +} + +.topbar .btn-dropdown { + width: auto; +} + +.topbar ul.dropdown-menu li a { + text-transform: uppercase; + font-weight: 600; + font-size: 12px; + color: #777; + -webkit-transition: background-color 0.1s ease-in-out; + -moz-transition: background-color 0.1s ease-in-out; + -ms-transition: background-color 0.1s ease-in-out; + -o-transition: background-color 0.1s ease-in-out; + transition: background-color 0.1s ease-in-out; +} + +.topbar ul.dropdown-menu li a:hover { + color: #5e5e5e; + background-color: #f3f3f3; +} .btn { - text-transform: uppercase; - font-weight: 600; - font-size: 12px; - border-width: 2px; - color: #777; - -webkit-transition: background-color 0.2s ease-in-out; - -moz-transition: background-color 0.2s ease-in-out; - -ms-transition: background-color 0.2s ease-in-out; - -o-transition: background-color 0.2s ease-in-out; - transition: background-color 0.2s ease-in-out; - -webkit-transition: border-color 0.2s ease-in-out; - -moz-transition: border-color 0.2s ease-in-out; - -ms-transition: border-color 0.2s ease-in-out; - -o-transition: border-color 0.2s ease-in-out; - transition: border-color 0.2s ease-in-out; - -webkit-transition: color 0.2s ease-in-out; - -moz-transition: color 0.2s ease-in-out; - -ms-transition: color 0.2s ease-in-out; - -o-transition: color 0.2s ease-in-out; - transition: color 0.2s ease-in-out; - outline: none; - outline-color: white; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } - .btn:hover { - color: #5e5e5e; - background-color: #f3f3f3; } - .btn:focus { - outline: none; - outline-color: white; - outline: none; - box-shadow: none; } - .btn.active { - outline-color: white; - outline: none; - box-shadow: none; } - .btn.btn-primary { - color: #69499a; - background-color: transparent; - border: 2px solid #9e84c5; } - .btn.btn-primary:hover { - background-color: #f7f3f9; - color: #8262b4; } - .btn.btn-warning { - color: #FFAC5E; - background-color: transparent; - border: 2px solid #FFAC5E; } - .btn.btn-warning:hover { - background-color: #fff8f2; - color: #ff922b; } - .btn.btn-success { - color: #86B457; - background-color: transparent; - border: 2px solid #86B457; } - .btn.btn-success:hover { - background-color: #f8fdf2; - color: #6c9543; } - .btn.btn-danger { - color: #dd4e58; - background-color: transparent; - border: 2px solid #dd4e58; } - .btn.btn-danger:hover { - background-color: #fcf1f1; - color: #d02834; } - .btn.active { - color: #69499a; - background-color: transparent; - border: 2px solid #9e84c5; } - .btn.active:hover { - background-color: #f7f3f9; - color: #8262b4; } - .btn.active.btn-noactive { - color: inherit; - background-color: inherit; - border: 2px solid #ccc; } - .btn.btn-mini { - font-size: 10px; - padding: 8px; } - .btn.btn-list { - font-size: 10px; - padding: 3px 5px 3px 5px; - margin-right: 5px; - border-radius: 3px; } + text-transform: uppercase; + font-weight: 600; + font-size: 12px; + border-width: 2px; + color: #777; + -webkit-transition: background-color 0.2s ease-in-out; + -moz-transition: background-color 0.2s ease-in-out; + -ms-transition: background-color 0.2s ease-in-out; + -o-transition: background-color 0.2s ease-in-out; + transition: background-color 0.2s ease-in-out; + -webkit-transition: border-color 0.2s ease-in-out; + -moz-transition: border-color 0.2s ease-in-out; + -ms-transition: border-color 0.2s ease-in-out; + -o-transition: border-color 0.2s ease-in-out; + transition: border-color 0.2s ease-in-out; + -webkit-transition: color 0.2s ease-in-out; + -moz-transition: color 0.2s ease-in-out; + -ms-transition: color 0.2s ease-in-out; + -o-transition: color 0.2s ease-in-out; + transition: color 0.2s ease-in-out; + outline: none; + outline-color: white; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.btn:hover { + color: #5e5e5e; + background-color: #f3f3f3; +} + +.btn:focus { + outline: none; + outline-color: white; + outline: none; + box-shadow: none; +} + +.btn.active { + outline-color: white; + outline: none; + box-shadow: none; +} + +.btn.btn-primary { + color: #69499a; + background-color: transparent; + border: 2px solid #9e84c5; +} + +.btn.btn-primary:hover { + background-color: #f7f3f9; + color: #8262b4; +} + +.btn.btn-warning { + color: #FFAC5E; + background-color: transparent; + border: 2px solid #FFAC5E; +} + +.btn.btn-warning:hover { + background-color: #fff8f2; + color: #ff922b; +} + +.btn.btn-success { + color: #86B457; + background-color: transparent; + border: 2px solid #86B457; +} + +.btn.btn-success:hover { + background-color: #f8fdf2; + color: #6c9543; +} + +.btn.btn-danger { + color: #dd4e58; + background-color: transparent; + border: 2px solid #dd4e58; +} + +.btn.btn-danger:hover { + background-color: #fcf1f1; + color: #d02834; +} + +.btn.active { + color: #69499a; + background-color: transparent; + border: 2px solid #9e84c5; +} + +.btn.active:hover { + background-color: #f7f3f9; + color: #8262b4; +} + +.btn.active.btn-noactive { + color: inherit; + background-color: inherit; + border: 2px solid #ccc; +} + +.btn.btn-mini { + font-size: 10px; + padding: 8px; +} + +.btn.btn-list { + font-size: 10px; + padding: 3px 5px 3px 5px; + margin-right: 5px; + border-radius: 3px; +} .topbar .btn.icon { - min-width: 50px; - height: 33px; - padding: 6px 0; } - .topbar .btn.icon svg { - height: 20px; - fill: currentColor; } + min-width: 50px; + height: 33px; + padding: 6px 0; +} + +.topbar .btn.icon svg { + height: 20px; + fill: currentColor; +} .list-group-item { - padding: 0; - border-width: 2px; - border-bottom-width: 2px; - border-radius: 2px; - margin-bottom: 15px; - margin-top: 15px; - -webkit-transition: background-color 0.3s ease-in-out; - -moz-transition: background-color 0.3s ease-in-out; - -ms-transition: background-color 0.3s ease-in-out; - -o-transition: background-color 0.3s ease-in-out; - transition: background-color 0.3s ease-in-out; } - .list-group-item .list-group-item-heading, .list-group-item .list-inline { - margin: 10px 15px 10px 15px; - padding: 0px 5px 0px 5px; } - .list-group-item .list-inline { - padding-left: 0px; - color: #777; - font-size: 13px; - height: 20px; } - .list-group-item .list-group-item-heading { - border-bottom: 2px solid #eee; - color: #555; } - .list-group-item .list-group-item-heading .heading-helper { - float: right; - font-weight: 600; - color: #939393; - font-size: 14px; } - .list-group-item .list-bar { - width: 100%; - height: 20px; } - .list-group-item.list-link:hover { - cursor: pointer; - background-color: #fafafa; } - .list-group-item.list-condensed-link:hover { - cursor: pointer; - background-color: #fafafa; } - .list-group-item.list-condensed-link, .list-group-item.list-condensed { - border-color: #E6E6E6; - margin-bottom: 4px; - margin-top: 4px; - height: 40px; - font-weight: 700; } - .list-group-item.list-condensed-link.double-line, .list-group-item.list-condensed.double-line { - height: 54px; } - .list-group-item.list-condensed-link .name, .list-group-item.list-condensed .name { - font-size: 15px; - padding-top: 6px; } - .list-group-item.list-condensed-link .name span, .list-group-item.list-condensed .name span { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 35%; - float: left; - display: inline-block; - padding-right: 4px; } - .list-group-item.list-condensed-link .name small, .list-group-item.list-condensed .name small { - display: inline-block; - padding-right: 8px; - padding-top: 2px; - font-size: 12px; - color: #939393; } - .list-group-item.list-condensed-link .metadata, .list-group-item.list-condensed .metadata { - display: block; - font-size: 12px; - float: left; - color: #939393; } - .list-group-item.list-condensed-link ul.sub, .list-group-item.list-condensed ul.sub { - margin: 0; - font-size: 12px; - color: #939393; - overflow: auto; } - .list-group-item.list-condensed-link ul.sub li, .list-group-item.list-condensed ul.sub li { - padding: 0; } - .list-group-item.list-condensed-link ul.sub::-webkit-scrollbar, .list-group-item.list-condensed ul.sub::-webkit-scrollbar { - display: none; - -webkit-appearance: none; } - .list-group-item .list-bar-horizontal { - width: 20px; - float: left; - height: 100%; - margin-right: 10px; } - .list-group-item.active { - -webkit-transition: border-color 0.1s linear; - -moz-transition: border-color 0.1s linear; - -ms-transition: border-color 0.1s linear; - -o-transition: border-color 0.1s linear; - transition: border-color 0.1s linear; - border-color: #9e84c5; } - .list-group-item.active .list-bar, .list-group-item.active .list-bar-horizontal { - -webkit-transition: background-color 0.1s linear; - -moz-transition: background-color 0.1s linear; - -ms-transition: background-color 0.1s linear; - -o-transition: background-color 0.1s linear; - transition: background-color 0.1s linear; - background-color: #9e84c5; } + padding: 0; + border-width: 2px; + border-bottom-width: 2px; + border-radius: 2px; + margin-bottom: 15px; + margin-top: 15px; + -webkit-transition: background-color 0.3s ease-in-out; + -moz-transition: background-color 0.3s ease-in-out; + -ms-transition: background-color 0.3s ease-in-out; + -o-transition: background-color 0.3s ease-in-out; + transition: background-color 0.3s ease-in-out; +} + +.list-group-item .list-group-item-heading, .list-group-item .list-inline { + margin: 10px 15px 10px 15px; + padding: 0px 5px 0px 5px; +} + +.list-group-item .list-inline { + padding-left: 0px; + color: #777; + font-size: 13px; + height: 20px; +} + +.list-group-item .list-group-item-heading { + border-bottom: 2px solid #eee; + color: #555; +} + +.list-group-item .list-group-item-heading .heading-helper { + float: right; + font-weight: 600; + color: #939393; + font-size: 14px; +} + +.list-group-item .list-bar { + width: 100%; + height: 20px; +} + +.list-group-item.list-link:hover { + cursor: pointer; + background-color: #fafafa; +} + +.list-group-item.list-condensed-link:hover { + cursor: pointer; + background-color: #fafafa; +} + +.list-group-item.list-condensed-link, .list-group-item.list-condensed { + border-color: #E6E6E6; + margin-bottom: 4px; + margin-top: 4px; + height: 40px; + font-weight: 700; +} + +.list-group-item.list-condensed-link.double-line, .list-group-item.list-condensed.double-line { + height: 54px; +} + +.list-group-item.list-condensed-link .name, .list-group-item.list-condensed .name { + font-size: 15px; + padding-top: 6px; +} + +.list-group-item.list-condensed-link .name span, .list-group-item.list-condensed .name span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 35%; + float: left; + display: inline-block; + padding-right: 4px; +} + +.list-group-item.list-condensed-link .name small, .list-group-item.list-condensed .name small { + display: inline-block; + padding-right: 8px; + padding-top: 2px; + font-size: 12px; + color: #939393; +} + +.list-group-item.list-condensed-link .metadata, .list-group-item.list-condensed .metadata { + display: block; + font-size: 12px; + float: left; + color: #939393; +} + +.list-group-item.list-condensed-link ul.sub, .list-group-item.list-condensed ul.sub { + margin: 0; + font-size: 12px; + color: #939393; + overflow: auto; +} + +.list-group-item.list-condensed-link ul.sub li, .list-group-item.list-condensed ul.sub li { + padding: 0; +} + +.list-group-item.list-condensed-link ul.sub::-webkit-scrollbar, .list-group-item.list-condensed ul.sub::-webkit-scrollbar { + display: none; + -webkit-appearance: none; +} + +.list-group-item .list-bar-horizontal { + width: 20px; + float: left; + height: 100%; + margin-right: 10px; +} + +.list-group-item.active { + -webkit-transition: border-color 0.1s linear; + -moz-transition: border-color 0.1s linear; + -ms-transition: border-color 0.1s linear; + -o-transition: border-color 0.1s linear; + transition: border-color 0.1s linear; + border-color: #9e84c5; +} + +.list-group-item.active .list-bar, .list-group-item.active .list-bar-horizontal { + -webkit-transition: background-color 0.1s linear; + -moz-transition: background-color 0.1s linear; + -ms-transition: background-color 0.1s linear; + -o-transition: background-color 0.1s linear; + transition: background-color 0.1s linear; + background-color: #9e84c5; +} .form-group .form-control { - -webkit-transition: border-color 0.2s ease-in-out; - -moz-transition: border-color 0.2s ease-in-out; - -ms-transition: border-color 0.2s ease-in-out; - -o-transition: border-color 0.2s ease-in-out; - transition: border-color 0.2s ease-in-out; - -webkit-transition: box-shadow 0.2s ease-in-out; - -moz-transition: box-shadow 0.2s ease-in-out; - -ms-transition: box-shadow 0.2s ease-in-out; - -o-transition: box-shadow 0.2s ease-in-out; - transition: box-shadow 0.2s ease-in-out; - -webkit-transition: border-color 0.2s ease-in-out; - -moz-transition: border-color 0.2s ease-in-out; - -ms-transition: border-color 0.2s ease-in-out; - -o-transition: border-color 0.2s ease-in-out; - transition: border-color 0.2s ease-in-out; } - .form-group .form-control.form-control-mini { - font-size: 12px; } + -webkit-transition: border-color 0.2s ease-in-out; + -moz-transition: border-color 0.2s ease-in-out; + -ms-transition: border-color 0.2s ease-in-out; + -o-transition: border-color 0.2s ease-in-out; + transition: border-color 0.2s ease-in-out; + -webkit-transition: box-shadow 0.2s ease-in-out; + -moz-transition: box-shadow 0.2s ease-in-out; + -ms-transition: box-shadow 0.2s ease-in-out; + -o-transition: box-shadow 0.2s ease-in-out; + transition: box-shadow 0.2s ease-in-out; + -webkit-transition: border-color 0.2s ease-in-out; + -moz-transition: border-color 0.2s ease-in-out; + -ms-transition: border-color 0.2s ease-in-out; + -o-transition: border-color 0.2s ease-in-out; + transition: border-color 0.2s ease-in-out; +} + +.form-group .form-control.form-control-mini { + font-size: 12px; +} + .form-group.valid .form-control { - border-color: #BBF085; - box-shadow: 0 0 5px #BBF085; } + border-color: #BBF085; + box-shadow: 0 0 5px #BBF085; +} + .form-group .input-group-addon { - background-color: #E6E6E6; } + background-color: #E6E6E6; +} textarea.form-control { - height: 130px; } + height: 130px; +} .ns-box { - position: fixed; - background: #666666; - padding: 20px; - line-height: 1.4; - z-index: 1000; - min-width: 400px; - pointer-events: none; - color: rgba(250, 251, 255, 0.95); - font-weight: 700; - font-size: 15px; - opacity: 0.8; } + position: fixed; + background: #666666; + padding: 20px; + line-height: 1.4; + z-index: 1000; + min-width: 400px; + pointer-events: none; + color: rgba(250, 251, 255, 0.95); + font-weight: 700; + font-size: 15px; + opacity: 0.8; +} .ns-box.ns-show { - pointer-events: auto; } + pointer-events: auto; +} .ns-box a { - color: inherit; - opacity: 0.7; - font-weight: 700; } + color: inherit; + opacity: 0.7; + font-weight: 700; +} .ns-box a:hover, .ns-box a:focus { - opacity: 1; } + opacity: 1; +} .ns-box p { - margin: 0; } + margin: 0; +} .ns-box.ns-show, .ns-box.ns-visible { - pointer-events: auto; } + pointer-events: auto; +} .ns-close { - width: 20px; - height: 20px; - position: absolute; - right: 4px; - top: 4px; - overflow: hidden; - text-indent: 100%; - cursor: pointer; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; } + width: 20px; + height: 20px; + position: absolute; + right: 4px; + top: 4px; + overflow: hidden; + text-indent: 100%; + cursor: pointer; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; +} .ns-close:hover, .ns-close:focus { - outline: none; } + outline: none; +} .ns-close::before, .ns-close::after { - content: ''; - position: absolute; - width: 3px; - height: 60%; - top: 50%; - left: 50%; - background: white; } + content: ''; + position: absolute; + width: 3px; + height: 60%; + top: 50%; + left: 50%; + background: white; +} .ns-close:hover::before, .ns-close:hover::after { - background: #fff; } + background: #fff; +} .ns-close::before { - -webkit-transform: translate(-50%, -50%) rotate(45deg); - transform: translate(-50%, -50%) rotate(45deg); } + -webkit-transform: translate(-50%, -50%) rotate(45deg); + transform: translate(-50%, -50%) rotate(45deg); +} .ns-close::after { - -webkit-transform: translate(-50%, -50%) rotate(-45deg); - transform: translate(-50%, -50%) rotate(-45deg); } + -webkit-transform: translate(-50%, -50%) rotate(-45deg); + transform: translate(-50%, -50%) rotate(-45deg); +} /* Growl-style notifications */ .ns-growl { - top: 30px; - left: 30px; - max-width: 300px; - border-radius: 5px; } + top: 30px; + left: 30px; + max-width: 300px; + border-radius: 5px; +} .ns-growl p { - margin: 0; - line-height: 1.3; } + margin: 0; + line-height: 1.3; +} [class^="ns-effect-"].ns-growl.ns-hide, [class*=" ns-effect-"].ns-growl.ns-hide { - -webkit-animation-direction: reverse; - animation-direction: reverse; } + -webkit-animation-direction: reverse; + animation-direction: reverse; +} /* Slide */ .ns-effect-slide { - top: 30px; } + top: 30px; +} .ns-effect-slide .ns-close:hover::before, .ns-effect-slide .ns-close:hover::after { - background: #fff; } + background: #fff; +} .ns-effect-slide.ns-show { - -webkit-animation-name: animSlideElastic; - animation-name: animSlideElastic; - -webkit-animation-duration: 1s; - animation-duration: 1s; - -webkit-animation-timing-function: linear; - animation-timing-function: linear; } + -webkit-animation-name: animSlideElastic; + animation-name: animSlideElastic; + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; +} @-webkit-keyframes animSlideElastic { - 0% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); } - 1.666667% { - -webkit-transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); - transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); } - 3.333333% { - -webkit-transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); - transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); } - 5% { - -webkit-transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); - transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); } - 6.666667% { - -webkit-transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); - transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); } - 8.333333% { - -webkit-transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); - transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); } - 10% { - -webkit-transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); - transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); } - 11.666667% { - -webkit-transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); - transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); } - 13.333333% { - -webkit-transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); - transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); } - 15% { - -webkit-transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); - transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); } - 16.666667% { - -webkit-transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); - transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); } - 18.333333% { - -webkit-transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); - transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); } - 20% { - -webkit-transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); - transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); } - 21.666667% { - -webkit-transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); - transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); } - 23.333333% { - -webkit-transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); - transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); } - 25% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); } - 26.666667% { - -webkit-transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); - transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); } - 28.333333% { - -webkit-transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); - transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); } - 30% { - -webkit-transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); - transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); } - 31.666667% { - -webkit-transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); - transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); } - 33.333333% { - -webkit-transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); - transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); } - 35% { - -webkit-transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); - transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); } - 36.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); } - 38.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); } - 40% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); } - 41.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); } - 43.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); } - 45% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); } - 46.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); } - 48.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); } - 50% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); } - 51.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); } - 53.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); } - 55% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); } - 56.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); } - 58.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); } - 60% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); } - 61.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); } - 63.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); } - 65% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); } - 66.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); } - 68.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); } - 70% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); } - 71.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); } - 73.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); } - 75% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); } - 76.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); } - 78.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); } - 80% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); } - 81.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); } - 83.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); } - 85% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); } - 86.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); } - 88.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); } - 90% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); } - 91.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); } - 93.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); } - 95% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); } - 96.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); } - 98.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); } - 100% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } } + 0% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); + } + 1.666667% { + -webkit-transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); + transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); + } + 3.333333% { + -webkit-transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); + transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); + } + 5% { + -webkit-transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); + transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); + } + 6.666667% { + -webkit-transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); + transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); + } + 8.333333% { + -webkit-transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); + transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); + } + 10% { + -webkit-transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); + transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); + } + 11.666667% { + -webkit-transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); + transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); + } + 13.333333% { + -webkit-transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); + transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); + } + 15% { + -webkit-transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); + transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); + } + 16.666667% { + -webkit-transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); + transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); + } + 18.333333% { + -webkit-transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); + transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); + } + 20% { + -webkit-transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); + transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); + } + 21.666667% { + -webkit-transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); + transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); + } + 23.333333% { + -webkit-transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); + transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); + } + 25% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); + } + 26.666667% { + -webkit-transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); + transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); + } + 28.333333% { + -webkit-transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); + transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); + } + 30% { + -webkit-transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); + transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); + } + 31.666667% { + -webkit-transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); + transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); + } + 33.333333% { + -webkit-transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); + transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); + } + 35% { + -webkit-transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); + transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); + } + 36.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); + } + 38.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); + } + 40% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); + } + 41.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); + } + 43.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); + } + 45% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); + } + 46.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); + } + 48.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); + } + 50% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); + } + 51.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); + } + 53.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); + } + 55% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); + } + 56.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); + } + 58.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); + } + 60% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); + } + 61.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); + } + 63.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); + } + 65% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); + } + 66.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); + } + 68.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); + } + 70% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); + } + 71.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); + } + 73.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); + } + 75% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); + } + 76.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); + } + 78.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); + } + 80% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); + } + 81.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); + } + 83.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); + } + 85% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); + } + 86.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); + } + 88.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); + } + 90% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); + } + 91.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); + } + 93.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); + } + 95% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); + } + 96.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); + } + 98.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); + } + 100% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + } +} + @keyframes animSlideElastic { - 0% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); } - 1.666667% { - -webkit-transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); - transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); } - 3.333333% { - -webkit-transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); - transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); } - 5% { - -webkit-transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); - transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); } - 6.666667% { - -webkit-transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); - transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); } - 8.333333% { - -webkit-transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); - transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); } - 10% { - -webkit-transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); - transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); } - 11.666667% { - -webkit-transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); - transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); } - 13.333333% { - -webkit-transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); - transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); } - 15% { - -webkit-transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); - transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); } - 16.666667% { - -webkit-transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); - transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); } - 18.333333% { - -webkit-transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); - transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); } - 20% { - -webkit-transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); - transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); } - 21.666667% { - -webkit-transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); - transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); } - 23.333333% { - -webkit-transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); - transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); } - 25% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); } - 26.666667% { - -webkit-transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); - transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); } - 28.333333% { - -webkit-transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); - transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); } - 30% { - -webkit-transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); - transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); } - 31.666667% { - -webkit-transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); - transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); } - 33.333333% { - -webkit-transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); - transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); } - 35% { - -webkit-transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); - transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); } - 36.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); } - 38.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); } - 40% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); } - 41.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); } - 43.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); } - 45% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); } - 46.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); } - 48.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); } - 50% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); } - 51.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); } - 53.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); } - 55% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); } - 56.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); } - 58.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); } - 60% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); } - 61.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); } - 63.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); } - 65% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); } - 66.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); } - 68.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); } - 70% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); } - 71.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); } - 73.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); } - 75% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); } - 76.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); } - 78.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); } - 80% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); } - 81.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); } - 83.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); } - 85% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); } - 86.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); } - 88.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); } - 90% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); } - 91.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); } - 93.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); } - 95% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); } - 96.666667% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); } - 98.333333% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); } - 100% { - -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } } + 0% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1); + } + 1.666667% { + -webkit-transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); + transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1); + } + 3.333333% { + -webkit-transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); + transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1); + } + 5% { + -webkit-transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); + transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1); + } + 6.666667% { + -webkit-transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); + transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1); + } + 8.333333% { + -webkit-transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); + transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1); + } + 10% { + -webkit-transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); + transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1); + } + 11.666667% { + -webkit-transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); + transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1); + } + 13.333333% { + -webkit-transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); + transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1); + } + 15% { + -webkit-transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); + transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1); + } + 16.666667% { + -webkit-transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); + transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1); + } + 18.333333% { + -webkit-transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); + transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1); + } + 20% { + -webkit-transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); + transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1); + } + 21.666667% { + -webkit-transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); + transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1); + } + 23.333333% { + -webkit-transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); + transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1); + } + 25% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1); + } + 26.666667% { + -webkit-transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); + transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1); + } + 28.333333% { + -webkit-transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); + transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1); + } + 30% { + -webkit-transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); + transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1); + } + 31.666667% { + -webkit-transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); + transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1); + } + 33.333333% { + -webkit-transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); + transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1); + } + 35% { + -webkit-transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); + transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1); + } + 36.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1); + } + 38.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1); + } + 40% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1); + } + 41.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1); + } + 43.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1); + } + 45% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1); + } + 46.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1); + } + 48.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1); + } + 50% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1); + } + 51.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1); + } + 53.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1); + } + 55% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1); + } + 56.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1); + } + 58.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1); + } + 60% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1); + } + 61.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1); + } + 63.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1); + } + 65% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1); + } + 66.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1); + } + 68.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1); + } + 70% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1); + } + 71.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1); + } + 73.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1); + } + 75% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1); + } + 76.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1); + } + 78.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1); + } + 80% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1); + } + 81.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1); + } + 83.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1); + } + 85% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1); + } + 86.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1); + } + 88.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1); + } + 90% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); + } + 91.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); + } + 93.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1); + } + 95% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1); + } + 96.666667% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1); + } + 98.333333% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1); + } + 100% { + -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + } +} + .ns-effect-slide.ns-hide { - -webkit-animation-name: animSlide; - animation-name: animSlide; - -webkit-animation-duration: 0.25s; - animation-duration: 0.25s; } + -webkit-animation-name: animSlide; + animation-name: animSlide; + -webkit-animation-duration: 0.25s; + animation-duration: 0.25s; +} @-webkit-keyframes animSlide { - 0% { - -webkit-transform: translate3d(-30px, 0, 0) translate3d(-100%, 0, 0); } - 100% { - -webkit-transform: translate3d(0, 0, 0); } } + 0% { + -webkit-transform: translate3d(-30px, 0, 0) translate3d(-100%, 0, 0); + } + 100% { + -webkit-transform: translate3d(0, 0, 0); + } +} + @keyframes animSlide { - 0% { - -webkit-transform: translate3d(-30px, 0, 0) translate3d(-100%, 0, 0); - transform: translate3d(-30px, 0, 0) translate3d(-100%, 0, 0); } - 100% { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); } } + 0% { + -webkit-transform: translate3d(-30px, 0, 0) translate3d(-100%, 0, 0); + transform: translate3d(-30px, 0, 0) translate3d(-100%, 0, 0); + } + 100% { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + html, body { - height: 100%; } + height: 100%; +} .wrapper { - min-height: 100%; - height: auto !important; - /* This line and the next line are not necessary unless you need IE6 support */ - height: 100%; - margin: 0 auto -60px; - /* the bottom margin is the negative value of the footer's height */ } + min-height: 100%; + height: auto !important; + /* This line and the next line are not necessary unless you need IE6 support */ + height: 100%; + margin: 0 auto -60px; + /* the bottom margin is the negative value of the footer's height */ +} .footer, .push { - height: 60px; - /* .push must be the same height as .footer */ } + height: 60px; + /* .push must be the same height as .footer */ +} @media (min-width: 1120px) { - .container { - width: 1100px; } } + .container { + width: 1100px; + } +} + @media (min-width: 1200px) { - .container { - width: 1200px; } } + .container { + width: 1200px; + } +} + @media (min-width: 1438px) { - .container { - width: 1400px; } } + .container { + width: 1400px; + } +} + a button:active { - outline: none; } + outline: none; +} .buffer-small { - height: 50px; } + height: 50px; +} @media (min-width: 991px) { - .border-left { - border-left: 1px #E6E6E6 solid; } - .border-left .padded-border { - padding-left: 30px; } } + .border-left { + border-left: 1px #E6E6E6 solid; + } + + .border-left .padded-border { + padding-left: 30px; + } +} + .padded-right-middle { - padding-right: 30px; } + padding-right: 30px; +} .no-margin { - margin: 0; } + margin: 0; +} .vertical-center { - margin-top: 200px; } + margin-top: 200px; +} .row.colored { - background-color: #f7f3f9; } + background-color: #f7f3f9; +} .bordered { - border-left: 2px solid #E6E6E6; } + border-left: 2px solid #E6E6E6; +} .bg-purple { - background-color: #9e84c5; } + background-color: #9e84c5; +} .bg-light-purple { - background-color: #f7f3f9; } + background-color: #f7f3f9; +} .bg-orange { - background-color: #FFAC5E; } + background-color: #FFAC5E; +} .bg-green { - background-color: #BBF085; } + background-color: #BBF085; +} .bg-dark-green { - background-color: #86B457; } + background-color: #86B457; +} .bg-red { - background-color: #dd4e58; } + background-color: #dd4e58; +} .bg-gray { - background-color: #939393; } + background-color: #939393; +} .bg-light-gray { - background-color: #E6E6E6; } + background-color: #E6E6E6; +} .action-bar { - min-height: 50px; - padding-top: 10px; - padding-bottom: 10px; } + min-height: 50px; + padding-top: 10px; + padding-bottom: 10px; +} .ember-list-view { - overflow: auto; - position: relative; - margin-bottom: 30px; } + overflow: auto; + position: relative; + margin-bottom: 30px; +} .ember-list-item-view { - position: absolute; - width: 100%; } + position: absolute; + width: 100%; +} .scrollable { - overflow: auto; - height: 800px; - margin-bottom: 30px; } + overflow: auto; + height: 800px; + margin-bottom: 30px; +} .elip-overflow { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; } + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} .do-logo { - opacity: 0.6; - margin-top: -3px; } + opacity: 0.6; + margin-top: -3px; +} /*# sourceMappingURL=base.css.map */ diff --git a/src/test/resources/consul_ui/static/base.css.map b/src/test/resources/consul_ui/static/base.css.map index 573c69f1..b6333075 100644 --- a/src/test/resources/consul_ui/static/base.css.map +++ b/src/test/resources/consul_ui/static/base.css.map @@ -1,7 +1,18 @@ { -"version": 3, -"mappings": "AAAA,IAAK;EACD,sBAAsB,EAAC,WAAW;EAClC,SAAS,EAAE,IAAI;EACf,KAAK,ECsBmB,IAAI;;ADnBhC,CAAE;EACE,KAAK,ECQmB,OAA0B;EDPlD,WAAW,EAAE,GAAG;EEPlB,kBAAkB,EFQI,sBAAqB;EEPxC,eAAe,EFOI,sBAAqB;EENvC,cAAc,EFMI,sBAAqB;EELtC,aAAa,EFKI,sBAAqB;EEJnC,UAAU,EFII,sBAAqB;EAEzC,OAAQ;IACJ,eAAe,EAAE,IAAI;IACrB,KAAK,EAAE,OAAoB;EAG/B,QAAS;IACL,KAAK,EAAE,OAAO;IAEd,cAAQ;MACJ,KAAK,ECLW,OAA0B;;ADUtD,IAAK;EACD,KAAK,ECZwB,OAAO;EDapC,gBAAgB,ECpBQ,OAAO;;ADuBnC,WAAY;EACR,SAAS,EAAE,IAAI;EACf,KAAK,EC1BmB,OAAO;;AD6BnC,KAAM;EACF,KAAK,EC/BmB,IAAI;;ADkChC,kBAAmB;EACf,KAAK,ECpCmB,IAAI;;ADuChC,EAAG;EACC,cAAc,EAAE,SAAS;EACzB,WAAW,EAAE,GAAG;EAChB,KAAK,ECxCmB,OAAO;;AD2CnC,cAAe;EACX,cAAc,EAAE,GAAG;EACnB,cAAc,EAAE,SAAS;EACzB,gBAAE;IACE,KAAK,EC/Ce,OAAO;;ADmDnC,GAAI;EACA,gBAAgB,ECrDQ,IAAI;EDsD5B,KAAK,EAAE,KAAK;EACZ,WAAW,EAAE,GAAG;EAChB,SAAS,EAAE,IAAI;;AAGnB,KAAM;EACF,WAAW,EAAE,GAAG;;AAGpB,MAAO;EACH,KAAK,EChEmB,IAAI;;AELhC,MAAO;EACH,YAAY,EAAE,GAAG;EACjB,YAAY,EFKY,OAAO;ECNjC,kBAAkB,ECEI,iCAAgC;EDDnD,eAAe,ECCI,iCAAgC;EDAlD,cAAc,ECAI,iCAAgC;EDCjD,aAAa,ECDI,iCAAgC;EDE9C,UAAU,ECFI,iCAAgC;EAEpD,qBAAe;IACX,OAAO,EAAE,QAAQ;IACjB,gBAAgB,EAAE,WAAW;IAC7B,YAAY,EAAE,GAAG;IACjB,YAAY,EFFQ,OAAO;EEK/B,qBAAe;IACX,OAAO,EAAE,gBAAgB;IACzB,SAAS,EAAE,IAAI;IACf,KAAK,EFTe,OAAO;IEU3B,KAAK,EFZe,IAAI;IEaxB,aAAa,EAAE,GAAG;IAClB,OAAO,EAAE,GAAG;IAEZ,2BAAM;MACF,SAAS,EAAE,IAAI;MACf,cAAc,EAAE,SAAS;MACzB,WAAW,EAAE,GAAG;MAChB,WAAW,EAAE,GAAG;MAChB,WAAW,EAAE,GAAG;IAIpB,8BAAS;MACP,cAAc,EAAE,IAAI;IAGtB,iCAAY;MACR,UAAU,EAAE,GAAG;MACf,KAAK,EAAE,KAAK;MACZ,WAAW,EAAE,GAAG;MAChB,KAAK,EF/BW,OAAO;MEgCvB,SAAS,EAAE,IAAI;EAKvB,qBAAe;IACX,OAAO,EAAE,eAAe;IACxB,SAAS,EAAE,IAAI;IACf,KAAK,EFxCe,OAAO;IEyC3B,KAAK,EF3Ce,IAAI;IE4CxB,aAAa,EAAE,GAAG;IAElB,2BAAM;MACF,SAAS,EAAE,IAAI;MACf,WAAW,EAAE,GAAG;IAGpB,iCAAY;MACR,UAAU,EAAE,GAAG;MACf,KAAK,EAAE,KAAK;MACZ,WAAW,EAAE,GAAG;MAChB,KAAK,EFrDW,OAAO;MEsDvB,SAAS,EAAE,IAAI;EAIvB,kBAAY;IACR,OAAO,EAAE,eAAe;IACxB,oBAAE;MACE,SAAS,EAAE,IAAI;MACf,KAAK,EF3CW,IAAI;IE6CxB,qBAAG;MACC,SAAS,EAAE,IAAI;IAEnB,2BAAS;MACL,SAAS,EAAE,IAAI;IAEnB,6BAAa;MACT,cAAc,EAAE,IAAI;EAI5B,iBAAW;IACP,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IDlFlB,kBAAkB,ECmFQ,4BAA2B;IDlFlD,eAAe,ECkFQ,4BAA2B;IDjFjD,cAAc,ECiFQ,4BAA2B;IDhFhD,aAAa,ECgFQ,4BAA2B;ID/E7C,UAAU,EC+EQ,4BAA2B;EAGnD,iBAAa;IACT,mBAAmB,EAAE,GAAG;EAIxB,oBAAG;IACC,MAAM,EAAE,CAAC;IACT,uBAAG;MACC,MAAM,EAAE,CAAC;MACT,MAAM,EAAE,CAAC;EAIrB,4BAAsB;IAClB,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,YAAY,EAAE,IAAI;IAClB,OAAO,EAAE,KAAK;EAGlB,kBAAc;IACV,mBAAmB,EAAE,GAAG;EAG5B,uBAAmB;IACf,MAAM,EAAE,OAAO;IACf,gBAAgB,EAAE,OAA6B;EAGnD,aAAS;IDpHX,kBAAkB,ECyHQ,wBAAuB;IDxH9C,eAAe,ECwHQ,wBAAuB;IDvH7C,cAAc,ECuHQ,wBAAuB;IDtH5C,aAAa,ECsHQ,wBAAuB;IDrHzC,UAAU,ECqHQ,wBAAuB;IAC3C,YAAY,EF5GQ,OAA0B;IEuG9C,8BAAgB;MACZ,YAAY,EFxGI,OAA0B;IE8G9C,wBAAW;MD5HjB,kBAAkB,EC6HQ,4BAA2B;MD5HlD,eAAe,EC4HQ,4BAA2B;MD3HjD,cAAc,EC2HQ,4BAA2B;MD1HhD,aAAa,EC0HQ,4BAA2B;MDzH7C,UAAU,ECyHQ,4BAA2B;MAC3C,gBAAgB,EFhHA,OAA0B;;AGdtD,UAAW;EACP,UAAU,EAAE,IAAI;EAChB,UAAU,EAAE,8CAA8C;EAC1D,eAAe,EAAE,SAAS;EAC1B,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;;AAIhB,OAAQ;EACJ,OAAO,EAAE,IAAI;EACb,WAAW,EAAE,IAAI;EACjB,cAAc,EAAE,IAAI;EACpB,aAAa,EAAE,IAAI;EACnB,UAAU,EAAE,IAAI;EAChB,aAAa,EAAE,cAAc;EAE7B,YAAK;IACD,UAAU,EAAE,IAAI;IAChB,SAAS,EAAE,KAAK;EAGpB,qBAAc;IACV,KAAK,EAAE,IAAI;EAMP,6BAAE;IACE,cAAc,EAAE,SAAS;IACzB,WAAW,EAAE,GAAG;IAChB,SAAS,EAAE,IAAI;IACf,KAAK,EH7BO,IAAI;ICJ9B,kBAAkB,EEkCgB,iCAAgC;IFjC/D,eAAe,EEiCgB,iCAAgC;IFhC9D,cAAc,EEgCgB,iCAAgC;IF/B7D,aAAa,EE+BgB,iCAAgC;IF9B1D,UAAU,EE8BgB,iCAAgC;IAEpD,mCAAQ;MACJ,KAAK,EAAE,OAAkB;MACzB,gBAAgB,EAAE,OAA6B;;ACvCnE,IAAK;EACD,cAAc,EAAE,SAAS;EACzB,WAAW,EAAE,GAAG;EAChB,SAAS,EAAE,IAAI;EACf,YAAY,EAAE,GAAG;EACjB,KAAK,EJAmB,IAAI;ECJ9B,kBAAkB,EGKI,iCAAgC;EHJnD,eAAe,EGII,iCAAgC;EHHlD,cAAc,EGGI,iCAAgC;EHFjD,aAAa,EGEI,iCAAgC;EHD9C,UAAU,EGCI,iCAAgC;EHLtD,kBAAkB,EGMI,6BAA4B;EHL/C,eAAe,EGKI,6BAA4B;EHJ9C,cAAc,EGII,6BAA4B;EHH7C,aAAa,EGGI,6BAA4B;EHF1C,UAAU,EGEI,6BAA4B;EHNlD,kBAAkB,EGOI,sBAAqB;EHNxC,eAAe,EGMI,sBAAqB;EHLvC,cAAc,EGKI,sBAAqB;EHJtC,aAAa,EGII,sBAAqB;EHHnC,UAAU,EGGI,sBAAqB;EACzC,OAAO,EAAE,IAAI;EACb,aAAa,EAAE,KAAK;EACpB,WAAW,EAAE,MAAM;EACnB,QAAQ,EAAE,MAAM;EAChB,aAAa,EAAE,QAAQ;EAEvB,UAAQ;IACJ,KAAK,EAAE,OAAkB;IACzB,gBAAgB,EAAE,OAA6B;EAGnD,UAAQ;IACJ,OAAO,EAAE,IAAI;IACb,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,IAAI;EAGpB,WAAS;IACL,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,IAAI;EAGpB,gBAAc;IACV,KAAK,EJpBoB,OAAO;IIqBhC,gBAAgB,EAAE,WAAW;IAC7B,MAAM,EAAE,iBAAiB;IAEzB,sBAAQ;MACJ,gBAAgB,EJvBA,OAAO;MIwBvB,KAAK,EAAE,OAAoB;EAInC,gBAAc;IACV,KAAK,EJvBe,OAAO;IIwB3B,gBAAgB,EAAE,WAAW;IAC7B,MAAM,EAAE,iBAAuB;IAE/B,sBAAQ;MACJ,gBAAgB,EAAE,OAA2B;MAC7C,KAAK,EAAE,OAA0B;EAKzC,gBAAc;IACV,KAAK,EJtCe,OAAO;IIuC3B,gBAAgB,EAAE,WAAW;IAC7B,MAAM,EAAE,iBAAqB;IAE7B,sBAAQ;MACJ,gBAAgB,EAAE,OAA0B;MAC5C,KAAK,EAAE,OAAwB;EAIvC,eAAa;IACT,KAAK,EJhDe,OAAI;IIiDxB,gBAAgB,EAAE,WAAW;IAC7B,MAAM,EAAE,iBAAc;IAEtB,qBAAQ;MACJ,gBAAgB,EAAE,OAAkB;MACpC,KAAK,EAAE,OAAiB;EAKhC,WAAS;IACL,KAAK,EJlEoB,OAAO;IImEhC,gBAAgB,EAAE,WAAW;IAC7B,MAAM,EAAE,iBAAiB;IAEzB,iBAAQ;MACJ,gBAAgB,EJrEA,OAAO;MIsEvB,KAAK,EAAE,OAAoB;IAG/B,wBAAe;MACX,KAAK,EAAE,OAAO;MACd,gBAAgB,EAAE,OAAO;MACzB,MAAM,EAAE,cAAc;EAK9B,aAAW;IACP,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,GAAG;EAGhB,aAAW;IACP,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,eAAe;IACxB,YAAY,EAAE,GAAG;IACjB,aAAa,EAAE,GAAG;;AAMxB,iBAAU;EACR,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,IAAI;EACZ,OAAO,EAAE,KAAK;EACd,qBAAI;IACF,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,YAAY;;ACtHxB,gBAAiB;EACb,OAAO,EAAE,CAAC;EACV,YAAY,EAAE,GAAG;EACjB,mBAAmB,EAAE,GAAG;EACxB,aAAa,EAAE,GAAG;EAClB,aAAa,EAAE,IAAI;EACnB,UAAU,EAAE,IAAI;EJLlB,kBAAkB,EIMI,iCAAgC;EJLnD,eAAe,EIKI,iCAAgC;EJJlD,cAAc,EIII,iCAAgC;EJHjD,aAAa,EIGI,iCAAgC;EJF9C,UAAU,EIEI,iCAAgC;EAEpD,wEAAuC;IACnC,MAAM,EAAE,mBAAmB;IAC3B,OAAO,EAAE,eAAe;EAG5B,6BAAa;IACT,YAAY,EAAE,GAAG;IACjB,KAAK,ELXe,IAAI;IKYxB,SAAS,EAAE,IAAI;IACf,MAAM,EAAE,IAAI;EAGhB,yCAAyB;IACrB,aAAa,EAAE,cAAc;IAC7B,KAAK,ELnBe,IAAI;IKqBxB,yDAAgB;MACZ,KAAK,EAAE,KAAK;MACZ,WAAW,EAAE,GAAG;MAChB,KAAK,ELtBW,OAAO;MKuBvB,SAAS,EAAE,IAAI;EAIvB,0BAAU;IACN,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;EAGhB,gCAAkB;IACd,MAAM,EAAE,OAAO;IACf,gBAAgB,EAAE,OAA6B;EAGnD,0CAA4B;IACxB,MAAM,EAAE,OAAO;IACf,gBAAgB,EAAE,OAA6B;EAGnD,qEAAwC;IACpC,YAAY,EL1CQ,OAAO;IK2C3B,aAAa,EAAE,GAAG;IAClB,UAAU,EAAE,GAAG;IAEf,MAAM,EAAE,IAAI;IAMZ,WAAW,EAAE,GAAG;IAJhB,6FAAc;MACV,MAAM,EAAE,IAAI;IAKhB,iFAAM;MACF,SAAS,EAAE,IAAI;MACf,WAAW,EAAE,GAAG;MAEhB,2FAAK;QACD,WAAW,EAAE,MAAM;QACnB,QAAQ,EAAE,MAAM;QAChB,aAAa,EAAE,QAAQ;QACvB,SAAS,EAAE,GAAG;QACd,KAAK,EAAE,IAAI;QACX,OAAO,EAAC,YAAY;QACpB,aAAa,EAAE,GAAG;MAGtB,6FAAM;QACF,OAAO,EAAE,YAAY;QACrB,aAAa,EAAE,GAAG;QAClB,WAAW,EAAE,GAAG;QAChB,SAAS,EAAE,IAAI;QACf,KAAK,EL1EO,OAAO;IK8E3B,yFAAU;MACN,OAAO,EAAE,KAAK;MACd,SAAS,EAAE,IAAI;MACf,KAAK,EAAE,IAAI;MACX,KAAK,ELlFW,OAAO;IKqF3B,mFAAO;MAKH,MAAM,EAAE,CAAC;MACT,SAAS,EAAE,IAAI;MACf,KAAK,EL5FW,OAAO;MK6FvB,QAAQ,EAAE,IAAI;MAPd,yFAAG;QACC,OAAO,EAAE,CAAC;MAQd,yHAAqB;QACjB,OAAO,EAAE,IAAI;QACb,kBAAkB,EAAE,IAAI;EAKpC,qCAAqB;IACjB,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,YAAY,EAAE,IAAI;EAItB,uBAAS;IJnHX,kBAAkB,EIoHQ,wBAAuB;IJnH9C,eAAe,EImHQ,wBAAuB;IJlH7C,cAAc,EIkHQ,wBAAuB;IJjH5C,aAAa,EIiHQ,wBAAuB;IJhHzC,UAAU,EIgHQ,wBAAuB;IAC3C,YAAY,ELvGQ,OAA0B;IKyG9C,+EAAgC;MJvHtC,kBAAkB,EIwHY,4BAA2B;MJvHtD,eAAe,EIuHY,4BAA2B;MJtHrD,cAAc,EIsHY,4BAA2B;MJrHpD,aAAa,EIqHY,4BAA2B;MJpHjD,UAAU,EIoHY,4BAA2B;MAC/C,gBAAgB,EL3GA,OAA0B;;AMdlD,yBAAc;ELAhB,kBAAkB,EKCQ,6BAA4B;ELAnD,eAAe,EKAQ,6BAA4B;ELClD,cAAc,EKDQ,6BAA4B;ELEjD,aAAa,EKFQ,6BAA4B;ELG9C,UAAU,EKHQ,6BAA4B;ELDtD,kBAAkB,EKEQ,2BAA0B;ELDjD,eAAe,EKCQ,2BAA0B;ELAhD,cAAc,EKAQ,2BAA0B;ELC/C,aAAa,EKDQ,2BAA0B;ELE5C,UAAU,EKFQ,2BAA0B;ELFpD,kBAAkB,EKGQ,6BAA4B;ELFnD,eAAe,EKEQ,6BAA4B;ELDlD,cAAc,EKCQ,6BAA4B;ELAjD,aAAa,EKAQ,6BAA4B;ELC9C,UAAU,EKDQ,6BAA4B;EAEhD,2CAAoB;IAChB,SAAS,EAAE,IAAI;AAKnB,+BAAc;EACV,YAAY,ENKI,OAAO;EMJvB,UAAU,EAAE,eAAoB;AAIxC,8BAAmB;EACf,gBAAgB,ENZI,OAAO;;AMgBnC,qBAAsB;EAClB,MAAM,EAAE,KAAK;;ACxBjB,OAAQ;EACJ,QAAQ,EAAE,KAAK;EACf,UAAU,EAAE,OAAmB;EAC/B,OAAO,EAAE,IAAI;EACb,WAAW,EAAE,GAAG;EAChB,OAAO,EAAE,IAAI;EACb,SAAS,EAAE,KAAK;EAChB,cAAc,EAAE,IAAI;EACpB,KAAK,EAAE,yBAAsB;EAC7B,WAAW,EAAE,GAAG;EAChB,SAAS,EAAE,IAAI;EACf,OAAO,EAAE,GAAG;;AAGhB,eAAgB;EACZ,cAAc,EAAE,IAAI;;AAGxB,SAAU;EACN,KAAK,EAAE,OAAO;EACd,OAAO,EAAE,GAAG;EACZ,WAAW,EAAE,GAAG;;AAGpB;eACgB;EACZ,OAAO,EAAE,CAAC;;AAGd,SAAU;EACN,MAAM,EAAE,CAAC;;AAGb;kBACmB;EACf,cAAc,EAAE,IAAI;;AAGxB,SAAU;EACN,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,GAAG;EACV,GAAG,EAAE,GAAG;EACR,QAAQ,EAAE,MAAM;EAChB,WAAW,EAAE,IAAI;EACjB,MAAM,EAAE,OAAO;EACf,2BAA2B,EAAE,MAAM;EACnC,mBAAmB,EAAE,MAAM;;AAG/B;eACgB;EACZ,OAAO,EAAE,IAAI;;AAGjB;gBACiB;EACb,OAAO,EAAE,EAAE;EACX,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,GAAG;EACX,GAAG,EAAE,GAAG;EACR,IAAI,EAAE,GAAG;EACT,UAAU,EAAE,KAAK;;AAGrB;sBACuB;EACnB,UAAU,EAAE,IAAI;;AAGpB,iBAAkB;EACd,iBAAiB,EAAE,mCAAkC;EACrD,SAAS,EAAE,mCAAkC;;AAGjD,gBAAiB;EACb,iBAAiB,EAAE,oCAAmC;EACtD,SAAS,EAAE,oCAAmC;;;AAMlD,SAAU;EACN,GAAG,EAAE,IAAI;EACT,IAAI,EAAE,IAAI;EACV,SAAS,EAAE,KAAK;EAChB,aAAa,EAAE,GAAG;;AAGtB,WAAY;EACR,MAAM,EAAE,CAAC;EACT,WAAW,EAAE,GAAG;;AAGpB;uCACwC;EACpC,2BAA2B,EAAE,OAAO;EACpC,mBAAmB,EAAE,OAAO;;;AAKhC,gBAAiB;EACb,GAAG,EAAE,IAAI;;AAGb;uCACwC;EACpC,UAAU,EAAE,IAAI;;AAGpB,wBAAyB;EACrB,sBAAsB,EAAE,gBAAgB;EACxC,cAAc,EAAE,gBAAgB;EAChC,0BAA0B,EAAE,EAAE;EAC9B,kBAAkB,EAAE,EAAE;EACtB,iCAAiC,EAAE,MAAM;EACzC,yBAAyB,EAAE,MAAM;;AAGrC,mCA8DC;EA7DG,EAAG;IAAE,iBAAiB,EAAE,4DAA4D;IAAE,SAAS,EAAE,4DAA4D;EAC7J,SAAU;IAAE,iBAAiB,EAAE,uEAAuE;IAAE,SAAS,EAAE,uEAAuE;EAC1L,SAAU;IAAE,iBAAiB,EAAE,uEAAuE;IAAE,SAAS,EAAE,uEAAuE;EAC1L,EAAG;IAAE,iBAAiB,EAAE,uEAAuE;IAAE,SAAS,EAAE,uEAAuE;EACnL,SAAU;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACtL,SAAU;IAAE,iBAAiB,EAAE,uEAAuE;IAAE,SAAS,EAAE,uEAAuE;EAC1L,GAAI;IAAE,iBAAiB,EAAE,sEAAsE;IAAE,SAAS,EAAE,sEAAsE;EAClL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,GAAI;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EAChL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,UAAW;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EACrL,GAAI;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EAChL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,UAAW;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EACrL,GAAI;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EAC9K,UAAW;IAAE,iBAAiB,EAAE,mEAAmE;IAAE,SAAS,EAAE,mEAAmE;EACnL,UAAW;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EACrL,GAAI;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EAC9K,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,6DAA6D;IAAE,SAAS,EAAE,6DAA6D;EACvK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,IAAK;IAAE,iBAAiB,EAAE,wDAAwD;IAAE,SAAS,EAAE,wDAAwD;AAG3J,2BA8DC;EA7DG,EAAG;IAAE,iBAAiB,EAAE,4DAA4D;IAAE,SAAS,EAAE,4DAA4D;EAC7J,SAAU;IAAE,iBAAiB,EAAE,uEAAuE;IAAE,SAAS,EAAE,uEAAuE;EAC1L,SAAU;IAAE,iBAAiB,EAAE,uEAAuE;IAAE,SAAS,EAAE,uEAAuE;EAC1L,EAAG;IAAE,iBAAiB,EAAE,uEAAuE;IAAE,SAAS,EAAE,uEAAuE;EACnL,SAAU;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACtL,SAAU;IAAE,iBAAiB,EAAE,uEAAuE;IAAE,SAAS,EAAE,uEAAuE;EAC1L,GAAI;IAAE,iBAAiB,EAAE,sEAAsE;IAAE,SAAS,EAAE,sEAAsE;EAClL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,GAAI;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EAChL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,UAAW;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EACrL,GAAI;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EAChL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,qEAAqE;IAAE,SAAS,EAAE,qEAAqE;EACvL,UAAW;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EACrL,GAAI;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EAC9K,UAAW;IAAE,iBAAiB,EAAE,mEAAmE;IAAE,SAAS,EAAE,mEAAmE;EACnL,UAAW;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EACrL,GAAI;IAAE,iBAAiB,EAAE,oEAAoE;IAAE,SAAS,EAAE,oEAAoE;EAC9K,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,6DAA6D;IAAE,SAAS,EAAE,6DAA6D;EACvK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EAClK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,UAAW;IAAE,iBAAiB,EAAE,8DAA8D;IAAE,SAAS,EAAE,8DAA8D;EACzK,GAAI;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EACpK,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,UAAW;IAAE,iBAAiB,EAAE,+DAA+D;IAAE,SAAS,EAAE,+DAA+D;EAC3K,IAAK;IAAE,iBAAiB,EAAE,wDAAwD;IAAE,SAAS,EAAE,wDAAwD;AAG3J,wBAAyB;EACrB,sBAAsB,EAAE,SAAS;EACjC,cAAc,EAAE,SAAS;EACzB,0BAA0B,EAAE,KAAK;EACjC,kBAAkB,EAAE,KAAK;;AAG7B,4BAGC;EAFG,EAAG;IAAE,iBAAiB,EAAE,iDAA6C;EACrE,IAAK;IAAE,iBAAiB,EAAE,oBAAkB;AAGhD,oBAGC;EAFG,EAAG;IAAE,iBAAiB,EAAE,iDAA6C;IAAE,SAAS,EAAE,iDAA6C;EAC/H,IAAK;IAAE,iBAAiB,EAAE,oBAAkB;IAAE,SAAS,EAAE,oBAAkB;AC/P/E,UAAW;EACT,MAAM,EAAE,IAAI;;AAGd,QAAS;EACP,UAAU,EAAE,IAAI;EAChB,MAAM,EAAE,eAAe;;EACvB,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,YAAY;;;AAGtB,cAAe;EACb,MAAM,EAAE,IAAI;;;AAGd,0BAA2B;EACzB,UAAW;IACT,KAAK,EAAE,MAAM;AAIjB,0BAA2B;EACzB,UAAW;IACT,KAAK,EAAE,MAAM;AAIjB,0BAA2B;EACzB,UAAW;IACT,KAAK,EAAE,MAAM;AAKb,eAAc;EACV,OAAO,EAAE,IAAI;;AAIrB,aAAc;EACZ,MAAM,EAAE,IAAI;;AAGd,yBAA0B;EACxB,YAAa;IACX,WAAW,EAAE,iBAA0B;IACvC,2BAAc;MACZ,YAAY,EAAE,IAAI;AAIxB,oBAAqB;EACnB,aAAa,EAAE,IAAI;;AAGrB,UAAW;EACP,MAAM,EAAE,CAAC;;AAGb,gBAAiB;EACb,UAAU,EAAE,KAAK;;AAIjB,YAAU;EACN,gBAAgB,ER3DI,OAAO;;AQ+DnC,SAAU;EACN,WAAW,EAAE,iBAA0B;;AAI3C,UAAW;EACP,gBAAgB,ERtEQ,OAA0B;;AQyEtD,gBAAiB;EACb,gBAAgB,ERzEQ,OAAO;;AQ4EnC,UAAW;EACP,gBAAgB,ERvEQ,OAAO;;AQ0EnC,SAAU;EACN,gBAAgB,ER/EQ,OAAO;;AQkFnC,cAAe;EACX,gBAAgB,ERlFQ,OAAO;;AQqFnC,OAAQ;EACJ,gBAAgB,ERrFQ,OAAI;;AQwFhC,QAAS;EACL,gBAAgB,ERvGQ,OAAO;;AQ0GnC,cAAe;EACX,gBAAgB,ER1GQ,OAAO;;AQ6GnC,WAAY;EACV,UAAU,EAAE,IAAI;EAChB,WAAW,EAAE,IAAI;EACjB,cAAc,EAAE,IAAI;;AAGtB,gBAAiB;EACf,QAAQ,EAAE,IAAI;EACd,QAAQ,EAAE,QAAQ;EAClB,aAAa,EAAE,IAAI;;AAGrB,qBAAsB;EACpB,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;;AAGb,WAAY;EACV,QAAQ,EAAE,IAAI;EACd,MAAM,EAAE,KAAK;EACb,aAAa,EAAE,IAAI;;AAGrB,cAAe;EACb,OAAO,EAAE,KAAK;EACd,QAAQ,EAAE,MAAM;EAChB,WAAW,EAAE,MAAM;EACnB,aAAa,EAAE,QAAQ;;AAGzB,QAAS;EACP,OAAO,EAAE,GAAG;EACZ,UAAU,EAAE,IAAI", -"sources": ["../styles/_type.scss","../styles/_variables.scss","../styles/_mixins.scss","../styles/_panels.scss","../styles/_nav.scss","../styles/_buttons.scss","../styles/_lists.scss","../styles/_forms.scss","../styles/_notifications.scss","../styles/base.scss"], -"names": [], -"file": "base.css" + "version": 3, + "mappings": "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", + "sources": [ + "../styles/_type.scss", + "../styles/_variables.scss", + "../styles/_mixins.scss", + "../styles/_panels.scss", + "../styles/_nav.scss", + "../styles/_buttons.scss", + "../styles/_lists.scss", + "../styles/_forms.scss", + "../styles/_notifications.scss", + "../styles/base.scss" + ], + "names": [], + "file": "base.css" } diff --git a/src/test/resources/consul_ui/static/loading-cylon-purple.svg b/src/test/resources/consul_ui/static/loading-cylon-purple.svg index 7107d1e7..092b8289 100644 --- a/src/test/resources/consul_ui/static/loading-cylon-purple.svg +++ b/src/test/resources/consul_ui/static/loading-cylon-purple.svg @@ -1,11 +1,21 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/src/test/resources/etc/configserver.json b/src/test/resources/etc/configserver.json index a40a5044..82fb9b23 100644 --- a/src/test/resources/etc/configserver.json +++ b/src/test/resources/etc/configserver.json @@ -1,7 +1,7 @@ { - "service": { - "name": "configserver", - "address": "127.0.0.1", - "port": 8888 - } + "service": { + "name": "configserver", + "address": "127.0.0.1", + "port": 8888 + } }