Checkstyle and jdk11 fix with spock
This commit is contained in:
@@ -21,6 +21,7 @@ public class WiremockTestsApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WiremockTestsApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
@@ -36,6 +37,7 @@ class Controller {
|
||||
public String home() {
|
||||
return this.service.go();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
@@ -51,7 +53,8 @@ class Service {
|
||||
}
|
||||
|
||||
public String go() {
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class).getBody();
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
public String getBase() {
|
||||
@@ -61,4 +64,5 @@ class Service {
|
||||
public void setBase(String base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
import com.github.tomakehurst.wiremock.junit.WireMockClassRule;
|
||||
|
||||
@ActiveProfiles("classrule")
|
||||
//tag::wiremock_test1[]
|
||||
// tag::wiremock_test1[]
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class WiremockForDocsClassRuleTests {
|
||||
@@ -29,12 +29,14 @@ public class WiremockForDocsClassRuleTests {
|
||||
@ClassRule
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(
|
||||
WireMockSpring.options().dynamicPort());
|
||||
//end::wiremock_test1[]
|
||||
|
||||
// end::wiremock_test1[]
|
||||
@Before
|
||||
public void setup() {
|
||||
this.service.setBase("http://localhost:" + wiremock.port());
|
||||
}
|
||||
//tag::wiremock_test2[]
|
||||
|
||||
// tag::wiremock_test2[]
|
||||
// A service that calls out over HTTP to localhost:${wiremock.port}
|
||||
@Autowired
|
||||
private Service service;
|
||||
@@ -43,11 +45,11 @@ public class WiremockForDocsClassRuleTests {
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
// Stubbing WireMock
|
||||
wiremock.stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
wiremock.stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
// We're asserting if WireMock responded properly
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
}
|
||||
//end::wiremock_test2[]
|
||||
// end::wiremock_test2[]
|
||||
@@ -33,5 +33,6 @@ public class WiremockForDocsMockServerApplicationTests {
|
||||
assertThat(this.service.go()).isEqualTo("Hello World");
|
||||
server.verify();
|
||||
}
|
||||
|
||||
}
|
||||
// end::wiremock_test[]
|
||||
|
||||
@@ -18,32 +18,37 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ActiveProfiles("docs")
|
||||
//tag::wiremock_test1[]
|
||||
// tag::wiremock_test1[]
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureWireMock(port = 0)
|
||||
public class WiremockForDocsTests {
|
||||
//end::wiremock_test1[]
|
||||
|
||||
@Autowired Environment environment;
|
||||
// end::wiremock_test1[]
|
||||
|
||||
@Autowired
|
||||
Environment environment;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
service.setBase("http://localhost:" + this.environment.getProperty("wiremock.server.port"));
|
||||
service.setBase("http://localhost:"
|
||||
+ this.environment.getProperty("wiremock.server.port"));
|
||||
}
|
||||
//tag::wiremock_test2[]
|
||||
|
||||
// tag::wiremock_test2[]
|
||||
// A service that calls out over HTTP
|
||||
@Autowired private Service service;
|
||||
@Autowired
|
||||
private Service service;
|
||||
|
||||
// Using the WireMock APIs in the normal way:
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
// Stubbing WireMock
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
// We're asserting if WireMock responded properly
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
}
|
||||
//end::wiremock_test2[]
|
||||
// end::wiremock_test2[]
|
||||
@@ -14,9 +14,8 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties="app.baseUrl=http://localhost:6060", webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(properties = "app.baseUrl=http://localhost:6060", webEnvironment = WebEnvironment.NONE)
|
||||
@AutoConfigureWireMock(port = 6060)
|
||||
public class WiremockImportApplicationTests {
|
||||
|
||||
@@ -25,8 +24,8 @@ public class WiremockImportApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
|
||||
public class WiremockMockServerApplicationTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -26,11 +26,12 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties="app.baseUrl=http://localhost:6061", webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(properties = "app.baseUrl=http://localhost:6061", webEnvironment = WebEnvironment.NONE)
|
||||
public class WiremockServerApplicationTests {
|
||||
|
||||
@ClassRule
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(WireMockSpring.options().port(6061));
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(
|
||||
WireMockSpring.options().port(6061));
|
||||
|
||||
@Rule
|
||||
public ExpectedException expected = ExpectedException.none();
|
||||
@@ -40,8 +41,8 @@ public class WiremockServerApplicationTests {
|
||||
|
||||
@Test
|
||||
public void hello() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ public class WiremockTestsApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WiremockTestsApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
@@ -35,6 +36,7 @@ class Controller {
|
||||
public String home() {
|
||||
return this.service.go();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
@@ -50,6 +52,8 @@ class Service {
|
||||
}
|
||||
|
||||
public String go() {
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class).getBody();
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
import com.github.tomakehurst.wiremock.junit.WireMockClassRule;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties="app.baseUrl=http://localhost:6063", webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(properties = "app.baseUrl=http://localhost:6063", webEnvironment = WebEnvironment.NONE)
|
||||
public class WiremockServerApplicationTests {
|
||||
|
||||
@ClassRule
|
||||
@@ -28,8 +28,8 @@ public class WiremockServerApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ public class WiremockTestsApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WiremockTestsApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
@@ -36,6 +37,7 @@ class Controller {
|
||||
public String home() {
|
||||
return this.service.go();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
@@ -51,6 +53,8 @@ class Service {
|
||||
}
|
||||
|
||||
public String go() {
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class).getBody();
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.github.tomakehurst.wiremock.junit.WireMockClassRule;
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest("app.baseUrl=https://localhost:6443")
|
||||
@AutoConfigureHttpClient
|
||||
@@ -32,8 +31,8 @@ public class WiremockHttpsServerApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,8 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties="app.baseUrl=http://localhost:6065", webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(properties = "app.baseUrl=http://localhost:6065", webEnvironment = WebEnvironment.NONE)
|
||||
@AutoConfigureWireMock(port = 6065)
|
||||
public class WiremockImportApplicationTests {
|
||||
|
||||
@@ -25,8 +24,8 @@ public class WiremockImportApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ public class WiremockImportContextPathApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
|
||||
public class WiremockMockServerApplicationTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -27,11 +27,12 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties="app.baseUrl=http://localhost:6067", webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(properties = "app.baseUrl=http://localhost:6067", webEnvironment = WebEnvironment.NONE)
|
||||
public class WiremockServerApplicationTests {
|
||||
|
||||
@ClassRule
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(WireMockSpring.options().port(6067));
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(
|
||||
WireMockSpring.options().port(6067));
|
||||
|
||||
@Rule
|
||||
public ExpectedException expected = ExpectedException.none();
|
||||
@@ -41,8 +42,8 @@ public class WiremockServerApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ public class WiremockTestsApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WiremockTestsApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
@@ -35,6 +36,7 @@ class Controller {
|
||||
public String home() {
|
||||
return this.service.go();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
@@ -50,6 +52,8 @@ class Service {
|
||||
}
|
||||
|
||||
public String go() {
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class).getBody();
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,23 +18,22 @@ import org.springframework.util.SocketUtils;
|
||||
|
||||
import com.github.tomakehurst.wiremock.junit.WireMockClassRule;
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest("app.baseUrl=https://localhost:7443")
|
||||
@ActiveProfiles("ssl")
|
||||
public class WiremockHttpsServerApplicationTests {
|
||||
|
||||
@ClassRule
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(
|
||||
WireMockSpring.options().httpsPort(7443).port(SocketUtils.findAvailableTcpPort()));
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(WireMockSpring
|
||||
.options().httpsPort(7443).port(SocketUtils.findAvailableTcpPort()));
|
||||
|
||||
@Autowired
|
||||
private Service service;
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ public class WiremockTestsApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WiremockTestsApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
@@ -35,6 +36,7 @@ class Controller {
|
||||
public String home() {
|
||||
return this.service.go();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
@@ -50,6 +52,8 @@ class Service {
|
||||
}
|
||||
|
||||
public String go() {
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class).getBody();
|
||||
return this.restTemplate.getForEntity(this.base + "/resource", String.class)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,9 +14,8 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties="app.baseUrl=http://localhost:7070", webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(properties = "app.baseUrl=http://localhost:7070", webEnvironment = WebEnvironment.NONE)
|
||||
@AutoConfigureWireMock(port = 7070)
|
||||
public class WiremockImportApplicationTests {
|
||||
|
||||
@@ -25,8 +24,8 @@ public class WiremockImportApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
|
||||
public class WiremockMockServerApplicationTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -18,19 +18,20 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
import com.github.tomakehurst.wiremock.junit.WireMockClassRule;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties="app.baseUrl=http://localhost:7071", webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(properties = "app.baseUrl=http://localhost:7071", webEnvironment = WebEnvironment.NONE)
|
||||
public class WiremockServerApplicationTests {
|
||||
|
||||
@ClassRule
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(WireMockSpring.options().port(7071));
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(
|
||||
WireMockSpring.options().port(7071));
|
||||
|
||||
@Autowired
|
||||
private Service service;
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/resource"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -49,20 +49,24 @@ class AetherFactories {
|
||||
private static final Log log = LogFactory.getLog(AetherFactories.class);
|
||||
|
||||
private static final String MAVEN_LOCAL_REPOSITORY_LOCATION = "maven.repo.local";
|
||||
|
||||
private static final String MAVEN_USER_SETTINGS_LOCATION = "org.apache.maven.user-settings";
|
||||
|
||||
private static final String MAVEN_GLOBAL_SETTINGS_LOCATION = "org.apache.maven.global-settings";
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
public static RepositorySystem newRepositorySystem() {
|
||||
DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
|
||||
locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
|
||||
locator.addService(RepositoryConnectorFactory.class,
|
||||
BasicRepositoryConnectorFactory.class);
|
||||
locator.addService(TransporterFactory.class, FileTransporterFactory.class);
|
||||
locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
|
||||
return locator.getService(RepositorySystem.class);
|
||||
}
|
||||
|
||||
public static RepositorySystemSession newSession(RepositorySystem system, boolean workOffline) {
|
||||
public static RepositorySystemSession newSession(RepositorySystem system,
|
||||
boolean workOffline) {
|
||||
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
|
||||
session.setOffline(workOffline);
|
||||
if (!workOffline) {
|
||||
@@ -71,16 +75,19 @@ class AetherFactories {
|
||||
session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_WARN);
|
||||
String localRepositoryDirectory = localRepositoryDirectory(workOffline);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Local Repository Directory set to [" + localRepositoryDirectory + "]. Work offline: [" + workOffline + "]");
|
||||
log.debug("Local Repository Directory set to [" + localRepositoryDirectory
|
||||
+ "]. Work offline: [" + workOffline + "]");
|
||||
}
|
||||
LocalRepository localRepo = new LocalRepository(localRepositoryDirectory);
|
||||
session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
|
||||
session.setLocalRepositoryManager(
|
||||
system.newLocalRepositoryManager(session, localRepo));
|
||||
return session;
|
||||
}
|
||||
|
||||
protected static String localRepositoryDirectory(boolean workOffline) {
|
||||
String localRepoLocationFromSettings = settings().getLocalRepository();
|
||||
String currentLocalRepo = readPropertyFromSystemProps(localRepoLocationFromSettings);
|
||||
String currentLocalRepo = readPropertyFromSystemProps(
|
||||
localRepoLocationFromSettings);
|
||||
if (workOffline) {
|
||||
return currentLocalRepo;
|
||||
}
|
||||
@@ -93,18 +100,21 @@ class AetherFactories {
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to create a new temporary directory, will generate a new one under temp dir");
|
||||
log.debug(
|
||||
"Failed to create a new temporary directory, will generate a new one under temp dir");
|
||||
}
|
||||
return System.getProperty("java.io.tmpdir") + File.separator + RANDOM.nextInt();
|
||||
return System.getProperty("java.io.tmpdir") + File.separator
|
||||
+ RANDOM.nextInt();
|
||||
}
|
||||
}
|
||||
|
||||
private static String readPropertyFromSystemProps(
|
||||
String localRepoLocationFromSettings) {
|
||||
String mavenLocalRepo = fromSystemPropOrEnv(MAVEN_LOCAL_REPOSITORY_LOCATION);
|
||||
return StringUtils.hasText(mavenLocalRepo) ? mavenLocalRepo :
|
||||
localRepoLocationFromSettings != null ? localRepoLocationFromSettings
|
||||
: System.getProperty("user.home") + File.separator + ".m2" + File.separator + "repository";
|
||||
return StringUtils.hasText(mavenLocalRepo) ? mavenLocalRepo
|
||||
: localRepoLocationFromSettings != null ? localRepoLocationFromSettings
|
||||
: System.getProperty("user.home") + File.separator + ".m2"
|
||||
+ File.separator + "repository";
|
||||
}
|
||||
|
||||
// system prop takes precedence over env var
|
||||
@@ -136,7 +146,8 @@ class AetherFactories {
|
||||
SettingsBuildingResult result;
|
||||
try {
|
||||
result = builder.build(request);
|
||||
} catch (SettingsBuildingException ex) {
|
||||
}
|
||||
catch (SettingsBuildingException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
return result.getEffectiveSettings();
|
||||
|
||||
@@ -54,28 +54,38 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
private static final Log log = LogFactory.getLog(AetherStubDownloader.class);
|
||||
|
||||
private static final String TEMP_DIR_PREFIX = "contracts";
|
||||
|
||||
private static final String ARTIFACT_EXTENSION = "jar";
|
||||
|
||||
private static final String LATEST_ARTIFACT_VERSION = "(,]";
|
||||
|
||||
private static final String LATEST_VERSION_IN_IVY = "+";
|
||||
|
||||
// Preloading class for the shutdown hook not to throw ClassNotFound
|
||||
private static final Class CLAZZ = TemporaryFileStorage.class;
|
||||
|
||||
private final List<RemoteRepository> remoteRepos;
|
||||
|
||||
private final RepositorySystem repositorySystem;
|
||||
|
||||
private final RepositorySystemSession session;
|
||||
|
||||
private final boolean workOffline;
|
||||
|
||||
private final boolean deleteStubsAfterTest;
|
||||
|
||||
public AetherStubDownloader(StubRunnerOptions stubRunnerOptions) {
|
||||
this.deleteStubsAfterTest = stubRunnerOptions.isDeleteStubsAfterTest();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will be resolving versions for the following options: [" + stubRunnerOptions + "]");
|
||||
log.debug("Will be resolving versions for the following options: ["
|
||||
+ stubRunnerOptions + "]");
|
||||
}
|
||||
this.remoteRepos = remoteRepositories(stubRunnerOptions);
|
||||
boolean remoteReposMissing = remoteReposMissing();
|
||||
switch (stubRunnerOptions.stubsMode) {
|
||||
case LOCAL:
|
||||
log.info("Remote repos not passed but the switch to work offline was set. " + "Stubs will be used from your local Maven repository.");
|
||||
log.info("Remote repos not passed but the switch to work offline was set. "
|
||||
+ "Stubs will be used from your local Maven repository.");
|
||||
break;
|
||||
case REMOTE:
|
||||
if (remoteReposMissing) {
|
||||
@@ -99,7 +109,6 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
|
||||
/**
|
||||
* Used by the Maven Plugin
|
||||
*
|
||||
* @param repositorySystem
|
||||
* @param remoteRepositories - remote artifact repositories
|
||||
* @param session
|
||||
@@ -111,26 +120,29 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
this.repositorySystem = repositorySystem;
|
||||
this.session = session;
|
||||
if (remoteReposMissing()) {
|
||||
log.error("Remote repositories for stubs are not specified and work offline flag wasn't passed");
|
||||
log.error(
|
||||
"Remote repositories for stubs are not specified and work offline flag wasn't passed");
|
||||
}
|
||||
this.workOffline = false;
|
||||
registerShutdownHook();
|
||||
}
|
||||
|
||||
private List<RemoteRepository> remoteRepositories(StubRunnerOptions stubRunnerOptions) {
|
||||
private List<RemoteRepository> remoteRepositories(
|
||||
StubRunnerOptions stubRunnerOptions) {
|
||||
if (stubRunnerOptions.stubRepositoryRoot == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
final String[] repos = stubRunnerOptions.getStubRepositoryRootAsString().split(",");
|
||||
final String[] repos = stubRunnerOptions.getStubRepositoryRootAsString()
|
||||
.split(",");
|
||||
final List<RemoteRepository> remoteRepos = new ArrayList<>();
|
||||
for (int i = 0; i < repos.length; i++) {
|
||||
if(StringUtils.hasText(repos[i])) {
|
||||
final RemoteRepository.Builder builder = new RemoteRepository.Builder("remote" + i, "default", repos[i])
|
||||
.setAuthentication(new AuthenticationBuilder()
|
||||
.addUsername(stubRunnerOptions.username)
|
||||
.addPassword(stubRunnerOptions.password)
|
||||
.build());
|
||||
if(stubRunnerOptions.getProxyOptions() != null) {
|
||||
if (StringUtils.hasText(repos[i])) {
|
||||
final RemoteRepository.Builder builder = new RemoteRepository.Builder(
|
||||
"remote" + i, "default", repos[i])
|
||||
.setAuthentication(new AuthenticationBuilder()
|
||||
.addUsername(stubRunnerOptions.username)
|
||||
.addPassword(stubRunnerOptions.password).build());
|
||||
if (stubRunnerOptions.getProxyOptions() != null) {
|
||||
final StubRunnerProxyOptions p = stubRunnerOptions.getProxyOptions();
|
||||
builder.setProxy(new Proxy(null, p.getProxyHost(), p.getProxyPort()));
|
||||
}
|
||||
@@ -155,12 +167,14 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
}
|
||||
Artifact artifact = new DefaultArtifact(stubsGroup, stubsModule, classifier,
|
||||
ARTIFACT_EXTENSION, resolvedVersion);
|
||||
ArtifactRequest request = new ArtifactRequest(artifact, this.remoteRepos, null);
|
||||
ArtifactRequest request = new ArtifactRequest(artifact, this.remoteRepos,
|
||||
null);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Resolving artifact [" + artifact
|
||||
+ "] using remote repositories " + this.remoteRepos);
|
||||
}
|
||||
ArtifactResult result = this.repositorySystem.resolveArtifact(this.session, request);
|
||||
ArtifactResult result = this.repositorySystem.resolveArtifact(this.session,
|
||||
request);
|
||||
log.info("Resolved artifact [" + artifact + "] to "
|
||||
+ result.getArtifact().getFile());
|
||||
File temporaryFile = unpackStubJarToATemporaryFolder(
|
||||
@@ -175,7 +189,8 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
throw new IllegalStateException(
|
||||
"Exception occurred while trying to download a stub for group ["
|
||||
+ stubsGroup + "] module [" + stubsModule
|
||||
+ "] and classifier [" + classifier + "] in " + this.remoteRepos,
|
||||
+ "] and classifier [" + classifier + "] in "
|
||||
+ this.remoteRepos,
|
||||
e);
|
||||
}
|
||||
}
|
||||
@@ -193,13 +208,16 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
if (StringUtils.isEmpty(version) || LATEST_VERSION_IN_IVY.equals(version)) {
|
||||
log.info("Desired version is [" + version
|
||||
+ "] - will try to resolve the latest version");
|
||||
return resolveHighestArtifactVersion(stubsGroup, stubsModule, classifier, LATEST_ARTIFACT_VERSION);
|
||||
return resolveHighestArtifactVersion(stubsGroup, stubsModule, classifier,
|
||||
LATEST_ARTIFACT_VERSION);
|
||||
}
|
||||
return resolveHighestArtifactVersion(stubsGroup, stubsModule, classifier, version);
|
||||
return resolveHighestArtifactVersion(stubsGroup, stubsModule, classifier,
|
||||
version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(StubConfiguration stubConfiguration) {
|
||||
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
StubConfiguration stubConfiguration) {
|
||||
String version = getVersion(stubConfiguration.groupId,
|
||||
stubConfiguration.artifactId, stubConfiguration.version,
|
||||
stubConfiguration.classifier);
|
||||
@@ -211,9 +229,9 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
if (unpackedJar == null) {
|
||||
return null;
|
||||
}
|
||||
return new AbstractMap.SimpleEntry<>(
|
||||
new StubConfiguration(stubConfiguration.groupId, stubConfiguration.artifactId, version,
|
||||
stubConfiguration.classifier), unpackedJar);
|
||||
return new AbstractMap.SimpleEntry<>(new StubConfiguration(
|
||||
stubConfiguration.groupId, stubConfiguration.artifactId, version,
|
||||
stubConfiguration.classifier), unpackedJar);
|
||||
}
|
||||
|
||||
private String resolveHighestArtifactVersion(String stubsGroup, String stubsModule,
|
||||
@@ -234,15 +252,19 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
throw new IllegalStateException("Cannot resolve version range", e);
|
||||
}
|
||||
if (rangeResult.getHighestVersion() == null) {
|
||||
throw new IllegalArgumentException("For groupId [" + stubsGroup + "] artifactId [" + stubsModule + "] "
|
||||
+ "and classifier [" + classifier + "] the version was not resolved! The following exceptions took place "
|
||||
throw new IllegalArgumentException("For groupId [" + stubsGroup
|
||||
+ "] artifactId [" + stubsModule + "] " + "and classifier ["
|
||||
+ classifier
|
||||
+ "] the version was not resolved! The following exceptions took place "
|
||||
+ rangeResult.getExceptions());
|
||||
}
|
||||
return rangeResult.getHighestVersion() == null ? null : rangeResult.getHighestVersion().toString();
|
||||
return rangeResult.getHighestVersion() == null ? null
|
||||
: rangeResult.getHighestVersion().toString();
|
||||
}
|
||||
|
||||
private static File unpackStubJarToATemporaryFolder(URI stubJarUri) {
|
||||
File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage.createTempDir(TEMP_DIR_PREFIX);
|
||||
File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage
|
||||
.createTempDir(TEMP_DIR_PREFIX);
|
||||
log.info("Unpacking stub from JAR [URI: " + stubJarUri + "]");
|
||||
unzipTo(new File(stubJarUri), tmpDirWhereStubsWillBeUnzipped);
|
||||
TemporaryFileStorage.add(tmpDirWhereStubsWillBeUnzipped);
|
||||
@@ -250,8 +272,8 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
}
|
||||
|
||||
private void registerShutdownHook() {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(
|
||||
() -> TemporaryFileStorage.cleanup(AetherStubDownloader.this.deleteStubsAfterTest)));
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> TemporaryFileStorage
|
||||
.cleanup(AetherStubDownloader.this.deleteStubsAfterTest)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,13 +9,16 @@ import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class AetherStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
|
||||
private static final Log log = LogFactory.getLog(AetherStubDownloaderBuilder.class);
|
||||
|
||||
@Override public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
@Override
|
||||
public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
if (stubRunnerOptions.stubsMode == StubRunnerProperties.StubsMode.CLASSPATH) {
|
||||
return null;
|
||||
}
|
||||
log.info("Will download stubs and contracts via Aether");
|
||||
return new AetherStubDownloader(stubRunnerOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,8 +22,11 @@ package org.springframework.cloud.contract.stubrunner;
|
||||
* @see StubRunner
|
||||
*/
|
||||
class Arguments {
|
||||
|
||||
final private StubRunnerOptions stubRunnerOptions;
|
||||
|
||||
final private String repositoryPath;
|
||||
|
||||
final private StubConfiguration stub;
|
||||
|
||||
Arguments(StubRunnerOptions stubRunnerOptions) {
|
||||
@@ -49,8 +52,11 @@ class Arguments {
|
||||
return this.stub;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Arguments{" + "stubRunnerOptions=" + this.stubRunnerOptions
|
||||
+ ", repositoryPath='" + this.repositoryPath + '\'' + ", stub=" + this.stub + '}';
|
||||
+ ", repositoryPath='" + this.repositoryPath + '\'' + ", stub="
|
||||
+ this.stub + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,7 +33,9 @@ class AvailablePortScanner {
|
||||
private static final int MAX_RETRY_COUNT = 1000;
|
||||
|
||||
private final int minPortNumber;
|
||||
|
||||
private final int maxPortNumber;
|
||||
|
||||
private final int maxRetryCount;
|
||||
|
||||
AvailablePortScanner(int minPortNumber, int maxPortNumber) {
|
||||
@@ -64,15 +66,16 @@ class AvailablePortScanner {
|
||||
}
|
||||
catch (IOException exception) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to execute callback (try: " + i + "/" + this.maxRetryCount
|
||||
+ ")", exception);
|
||||
log.debug("Failed to execute callback (try: " + i + "/"
|
||||
+ this.maxRetryCount + ")", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new NoPortAvailableException(this.minPortNumber, this.maxPortNumber);
|
||||
}
|
||||
|
||||
private <T> T executeLogicForAvailablePort(int portToScan, PortCallback<T> closure) throws IOException {
|
||||
private <T> T executeLogicForAvailablePort(int portToScan, PortCallback<T> closure)
|
||||
throws IOException {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Trying to execute closure with port [" + portToScan + "]");
|
||||
}
|
||||
@@ -93,20 +96,28 @@ class AvailablePortScanner {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class NoPortAvailableException extends RuntimeException {
|
||||
|
||||
NoPortAvailableException(int lowerBound, int upperBound) {
|
||||
super("Could not find available port in range " + lowerBound + ":" + upperBound);
|
||||
super("Could not find available port in range " + lowerBound + ":"
|
||||
+ upperBound);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class InvalidPortRange extends RuntimeException {
|
||||
|
||||
InvalidPortRange(int lowerBound, int upperBound) {
|
||||
super("Invalid bounds exceptions, min port [" + lowerBound
|
||||
+ "] is greater to max port [" + upperBound + "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface PortCallback<T> {
|
||||
|
||||
T call(int port) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -54,7 +54,9 @@ public class BatchStubRunner implements StubRunning {
|
||||
for (StubRunner stubRunner : this.stubRunners) {
|
||||
try {
|
||||
return stubRunner.findStubUrl(groupId, artifactId);
|
||||
} catch (StubNotFoundException e) {}
|
||||
}
|
||||
catch (StubNotFoundException e) {
|
||||
}
|
||||
}
|
||||
throw new StubNotFoundException(groupId, artifactId);
|
||||
}
|
||||
@@ -64,7 +66,9 @@ public class BatchStubRunner implements StubRunning {
|
||||
for (StubRunner stubRunner : this.stubRunners) {
|
||||
try {
|
||||
return stubRunner.findStubUrl(ivyNotation);
|
||||
} catch (StubNotFoundException e) {}
|
||||
}
|
||||
catch (StubNotFoundException e) {
|
||||
}
|
||||
}
|
||||
throw new StubNotFoundException(ivyNotation);
|
||||
}
|
||||
@@ -175,4 +179,5 @@ public class BatchStubRunner implements StubRunning {
|
||||
stubRunner.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,35 +28,44 @@ import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessag
|
||||
public class BatchStubRunnerFactory {
|
||||
|
||||
private final StubRunnerOptions stubRunnerOptions;
|
||||
|
||||
private final StubDownloader stubDownloader;
|
||||
|
||||
private final MessageVerifier<?> contractVerifierMessaging;
|
||||
|
||||
public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions) {
|
||||
this(stubRunnerOptions, new NoOpStubMessages());
|
||||
}
|
||||
|
||||
public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, MessageVerifier verifier) {
|
||||
public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions,
|
||||
MessageVerifier verifier) {
|
||||
this(stubRunnerOptions, aetherStubDownloader(stubRunnerOptions), verifier);
|
||||
}
|
||||
|
||||
private static StubDownloader aetherStubDownloader(StubRunnerOptions stubRunnerOptions) {
|
||||
private static StubDownloader aetherStubDownloader(
|
||||
StubRunnerOptions stubRunnerOptions) {
|
||||
StubDownloaderBuilderProvider provider = new StubDownloaderBuilderProvider();
|
||||
return provider.get(stubRunnerOptions);
|
||||
}
|
||||
|
||||
public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, StubDownloader stubDownloader) {
|
||||
public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions,
|
||||
StubDownloader stubDownloader) {
|
||||
this(stubRunnerOptions, stubDownloader, new NoOpStubMessages());
|
||||
}
|
||||
|
||||
public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, StubDownloader stubDownloader, MessageVerifier<?> contractVerifierMessaging) {
|
||||
public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions,
|
||||
StubDownloader stubDownloader, MessageVerifier<?> contractVerifierMessaging) {
|
||||
this.stubRunnerOptions = stubRunnerOptions;
|
||||
this.stubDownloader = stubDownloader;
|
||||
this.contractVerifierMessaging = contractVerifierMessaging;
|
||||
}
|
||||
|
||||
public BatchStubRunner buildBatchStubRunner() {
|
||||
StubRunnerFactory stubRunnerFactory = new StubRunnerFactory(this.stubRunnerOptions, this.stubDownloader, this.contractVerifierMessaging);
|
||||
return new BatchStubRunner(stubRunnerFactory.createStubsFromServiceConfiguration());
|
||||
StubRunnerFactory stubRunnerFactory = new StubRunnerFactory(
|
||||
this.stubRunnerOptions, this.stubDownloader,
|
||||
this.contractVerifierMessaging);
|
||||
return new BatchStubRunner(
|
||||
stubRunnerFactory.createStubsFromServiceConfiguration());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,12 +23,13 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
|
||||
/**
|
||||
* Stub downloader that picks stubs and contracts from the provided resource.
|
||||
* If {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties#stubsMode} is set
|
||||
* to {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties.StubsMode#CLASSPATH}
|
||||
* Stub downloader that picks stubs and contracts from the provided resource. If
|
||||
* {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties#stubsMode}
|
||||
* is set to
|
||||
* {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties.StubsMode#CLASSPATH}
|
||||
* then classpath is searched according to what has been passed in
|
||||
* {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties#ids}. The
|
||||
* pattern to search for stubs looks like this
|
||||
* {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties#ids}.
|
||||
* The pattern to search for stubs looks like this
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code META-INF/group.id/artifactid/ ** /*.* }</li>
|
||||
@@ -51,10 +52,10 @@ import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
*/
|
||||
public class ClasspathStubProvider implements StubDownloaderBuilder {
|
||||
|
||||
private static final Log log = LogFactory
|
||||
.getLog(ClasspathStubProvider.class);
|
||||
private static final Log log = LogFactory.getLog(ClasspathStubProvider.class);
|
||||
|
||||
private static final int TEMP_DIR_ATTEMPTS = 10000;
|
||||
|
||||
private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
|
||||
new DefaultResourceLoader());
|
||||
|
||||
@@ -72,35 +73,41 @@ public class ClasspathStubProvider implements StubDownloaderBuilder {
|
||||
List<String> paths = toPaths(repoRoots);
|
||||
List<Resource> resources = resolveResources(paths);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("For paths " + paths + " found following resources " + resources);
|
||||
log.debug("For paths " + paths + " found following resources "
|
||||
+ resources);
|
||||
}
|
||||
if (resources.isEmpty()) {
|
||||
throw new IllegalStateException("No stubs were found on classpath for [" + config.getGroupId() + ":" + config.getArtifactId() + "]");
|
||||
throw new IllegalStateException(
|
||||
"No stubs were found on classpath for [" + config.getGroupId()
|
||||
+ ":" + config.getArtifactId() + "]");
|
||||
}
|
||||
final File tmp = createTempDir();
|
||||
if (stubRunnerOptions.isDeleteStubsAfterTest()) {
|
||||
tmp.deleteOnExit();
|
||||
}
|
||||
Pattern groupAndArtifactPattern = Pattern.compile(
|
||||
"^(.*)(" + config.getGroupId() + "." + config.getArtifactId() + ")(.*)$");
|
||||
Pattern groupAndArtifactPattern = Pattern.compile("^(.*)("
|
||||
+ config.getGroupId() + "." + config.getArtifactId() + ")(.*)$");
|
||||
String version = config.getVersion();
|
||||
for (Resource resource : resources) {
|
||||
try {
|
||||
String relativePath = relativePathPicker(resource, groupAndArtifactPattern);
|
||||
String relativePath = relativePathPicker(resource,
|
||||
groupAndArtifactPattern);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Relative path for resource is [" + relativePath + "]");
|
||||
log.debug("Relative path for resource is [" + relativePath
|
||||
+ "]");
|
||||
}
|
||||
// the relative path is OS agnostic and contains / only
|
||||
int lastIndexOf = relativePath.lastIndexOf("/");
|
||||
String relativePathWithoutFile = lastIndexOf > -1 ?
|
||||
relativePath.substring(0, lastIndexOf) :
|
||||
relativePath;
|
||||
String relativePathWithoutFile = lastIndexOf > -1
|
||||
? relativePath.substring(0, lastIndexOf) : relativePath;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Relative path without file name is [" + relativePathWithoutFile + "]");
|
||||
log.debug("Relative path without file name is ["
|
||||
+ relativePathWithoutFile + "]");
|
||||
}
|
||||
Path directory = Files.createDirectories(
|
||||
new File(tmp, relativePathWithoutFile).toPath());
|
||||
File newFile = new File(directory.toFile(), resource.getFilename());
|
||||
File newFile = new File(directory.toFile(),
|
||||
resource.getFilename());
|
||||
if (!newFile.exists() && !isDirectory(resource)) {
|
||||
try (InputStream stream = resource.getInputStream()) {
|
||||
Files.copy(stream, newFile.toPath());
|
||||
@@ -109,31 +116,38 @@ public class ClasspathStubProvider implements StubDownloaderBuilder {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Stored file [" + newFile + "]");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Exception occurred while trying to create dirs", e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
log.info("Unpacked files for [" + config.getGroupId() + ":" + config.getArtifactId()
|
||||
+ ":" + version + "] to folder [" + tmp + "]");
|
||||
log.info("Unpacked files for [" + config.getGroupId() + ":"
|
||||
+ config.getArtifactId() + ":" + version + "] to folder [" + tmp
|
||||
+ "]");
|
||||
return new AbstractMap.SimpleEntry<>(
|
||||
new StubConfiguration(config.getGroupId(), config.getArtifactId(), version,
|
||||
config.getClassifier()), tmp);
|
||||
new StubConfiguration(config.getGroupId(), config.getArtifactId(),
|
||||
version, config.getClassifier()),
|
||||
tmp);
|
||||
}
|
||||
|
||||
boolean isDirectory(Resource resource) {
|
||||
try {
|
||||
return resource.getFile().isDirectory();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Exception occurred while trying to convert path to file for resource [" + resource + "]", e);
|
||||
log.trace(
|
||||
"Exception occurred while trying to convert path to file for resource ["
|
||||
+ resource + "]",
|
||||
e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String relativePathPicker(Resource resource,
|
||||
Pattern groupAndArtifactPattern) throws IOException {
|
||||
String relativePathPicker(Resource resource, Pattern groupAndArtifactPattern)
|
||||
throws IOException {
|
||||
String uri = resource.getURI().toString();
|
||||
Matcher groupAndArtifactMatcher = groupAndArtifactPattern.matcher(uri);
|
||||
if (groupAndArtifactMatcher.matches()) {
|
||||
@@ -165,7 +179,8 @@ public class ClasspathStubProvider implements StubDownloaderBuilder {
|
||||
resources.addAll(list);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Exception occurred while trying to fetch resources from [" + path + "]");
|
||||
log.error("Exception occurred while trying to fetch resources from ["
|
||||
+ path + "]");
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
@@ -175,11 +190,12 @@ public class ClasspathStubProvider implements StubDownloaderBuilder {
|
||||
private List<RepoRoot> repoRoot(StubRunnerOptions stubRunnerOptions,
|
||||
StubConfiguration configuration) {
|
||||
if (stubRunnerOptions.getStubRepositoryRoot() != null) {
|
||||
return Collections
|
||||
.singletonList(new RepoRoot(stubRunnerOptions.getStubRepositoryRootAsString()));
|
||||
return Collections.singletonList(
|
||||
new RepoRoot(stubRunnerOptions.getStubRepositoryRootAsString()));
|
||||
}
|
||||
else {
|
||||
String path = "/**/" + configuration.getGroupId() + "/" + configuration.getArtifactId();
|
||||
String path = "/**/" + configuration.getGroupId() + "/"
|
||||
+ configuration.getArtifactId();
|
||||
return Arrays.asList(new RepoRoot("classpath*:/META-INF" + path, "/**/*.*"),
|
||||
new RepoRoot("classpath*:/contracts" + path, "/**/*.*"),
|
||||
new RepoRoot("classpath*:/mappings" + path, "/**/*.*"));
|
||||
@@ -196,14 +212,15 @@ public class ClasspathStubProvider implements StubDownloaderBuilder {
|
||||
return tempDir;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Failed to create directory within " + TEMP_DIR_ATTEMPTS
|
||||
+ " attempts (tried " + baseName + "0 to " + baseName + (
|
||||
TEMP_DIR_ATTEMPTS - 1) + ")");
|
||||
throw new IllegalStateException("Failed to create directory within "
|
||||
+ TEMP_DIR_ATTEMPTS + " attempts (tried " + baseName + "0 to " + baseName
|
||||
+ (TEMP_DIR_ATTEMPTS - 1) + ")");
|
||||
}
|
||||
|
||||
private static class RepoRoot {
|
||||
|
||||
final String repoRoot;
|
||||
|
||||
final String fullPath;
|
||||
|
||||
RepoRoot(String repoRoot) {
|
||||
@@ -215,5 +232,7 @@ public class ClasspathStubProvider implements StubDownloaderBuilder {
|
||||
this.repoRoot = repoRoot;
|
||||
this.fullPath = repoRoot + suffix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,12 +36,14 @@ class CompositeStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
this.builders = builders;
|
||||
}
|
||||
|
||||
@Override public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
@Override
|
||||
public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
if (this.builders == null) {
|
||||
return null;
|
||||
}
|
||||
return new CompositeStubDownloader(this.builders, stubRunnerOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CompositeStubDownloader implements StubDownloader {
|
||||
@@ -49,6 +51,7 @@ class CompositeStubDownloader implements StubDownloader {
|
||||
private static final Log log = LogFactory.getLog(CompositeStubDownloader.class);
|
||||
|
||||
private final List<StubDownloaderBuilder> builders;
|
||||
|
||||
private final StubRunnerOptions stubRunnerOptions;
|
||||
|
||||
CompositeStubDownloader(List<StubDownloaderBuilder> builders,
|
||||
@@ -56,14 +59,13 @@ class CompositeStubDownloader implements StubDownloader {
|
||||
this.builders = builders;
|
||||
this.stubRunnerOptions = stubRunnerOptions;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Registered following stub downloaders " + this.builders
|
||||
.stream()
|
||||
.map(b -> b.getClass().getName())
|
||||
.collect(Collectors.toList()));
|
||||
log.debug("Registered following stub downloaders " + this.builders.stream()
|
||||
.map(b -> b.getClass().getName()).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
@Override
|
||||
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
StubConfiguration stubConfiguration) {
|
||||
for (StubDownloaderBuilder builder : this.builders) {
|
||||
StubDownloader downloader = builder.build(this.stubRunnerOptions);
|
||||
@@ -71,21 +73,27 @@ class CompositeStubDownloader implements StubDownloader {
|
||||
continue;
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Found a matching stub downloader [" + downloader.getClass().getName() + "]");
|
||||
log.debug("Found a matching stub downloader ["
|
||||
+ downloader.getClass().getName() + "]");
|
||||
}
|
||||
Map.Entry<StubConfiguration, File> entry = downloader
|
||||
.downloadAndUnpackStubJar(stubConfiguration);
|
||||
if (entry != null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Found a matching entry [" + entry + "] by stub downloader [" + downloader.getClass().getName() + "]");
|
||||
log.debug(
|
||||
"Found a matching entry [" + entry + "] by stub downloader ["
|
||||
+ downloader.getClass().getName() + "]");
|
||||
}
|
||||
return entry;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
log.warn("Stub Downloader [" + downloader.getClass().getName() + "] "
|
||||
+ "failed to find an entry for [" + stubConfiguration.toColonSeparatedDependencyNotation() + "]. "
|
||||
+ "failed to find an entry for ["
|
||||
+ stubConfiguration.toColonSeparatedDependencyNotation() + "]. "
|
||||
+ "Will proceed to the next one");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,24 +30,28 @@ import org.springframework.util.StringUtils;
|
||||
* inclusion patterns
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ContractDownloader {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
private static final Log log = LogFactory
|
||||
.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final StubDownloader stubDownloader;
|
||||
|
||||
private final StubConfiguration contractsJarStubConfiguration;
|
||||
|
||||
private final String contractsPath;
|
||||
|
||||
private final String projectGroupId;
|
||||
|
||||
private final String projectArtifactId;
|
||||
|
||||
private final String projectVersion;
|
||||
|
||||
public ContractDownloader(StubDownloader stubDownloader,
|
||||
StubConfiguration contractsJarStubConfiguration,
|
||||
String contractsPath, String projectGroupId, String projectArtifactId,
|
||||
String projectVersion) {
|
||||
StubConfiguration contractsJarStubConfiguration, String contractsPath,
|
||||
String projectGroupId, String projectArtifactId, String projectVersion) {
|
||||
this.stubDownloader = stubDownloader;
|
||||
this.contractsJarStubConfiguration = contractsJarStubConfiguration;
|
||||
this.contractsPath = contractsPath;
|
||||
@@ -58,10 +62,11 @@ public class ContractDownloader {
|
||||
|
||||
/**
|
||||
* Downloads JAR containing all the contracts. Plugin configuration gets updated with
|
||||
* the inclusion pattern for the downloaded contracts. The JAR with the contracts contains all
|
||||
* the contracts for all the projects. We're interested only in its subset.
|
||||
*
|
||||
* @param config - Plugin configuration that will get updated with the inclusion pattern
|
||||
* the inclusion pattern for the downloaded contracts. The JAR with the contracts
|
||||
* contains all the contracts for all the projects. We're interested only in its
|
||||
* subset.
|
||||
* @param config - Plugin configuration that will get updated with the inclusion
|
||||
* pattern
|
||||
* @return location of the unpacked downloaded stubs
|
||||
*/
|
||||
public File unpackedDownloadedContracts(ContractVerifierConfigProperties config) {
|
||||
@@ -70,15 +75,16 @@ public class ContractDownloader {
|
||||
return contractsDirectory;
|
||||
}
|
||||
|
||||
public ContractVerifierConfigProperties updatePropertiesWithInclusion(File contractsDirectory,
|
||||
ContractVerifierConfigProperties config) {
|
||||
public ContractVerifierConfigProperties updatePropertiesWithInclusion(
|
||||
File contractsDirectory, ContractVerifierConfigProperties config) {
|
||||
String pattern;
|
||||
String includedAntPattern;
|
||||
if (StringUtils.hasText(this.contractsPath)) {
|
||||
pattern = patternFromProperty(contractsDirectory);
|
||||
log.info("Will pick a pattern from the contractPath property");
|
||||
includedAntPattern = wrapWithAntPattern(contractsPath());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
log.info("Will pick a pattern from group id and artifact id");
|
||||
if (hasGavInPath(contractsDirectory)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -88,12 +94,14 @@ public class ContractDownloader {
|
||||
// we're already under proper folder (for the given group and artifact)
|
||||
pattern = fileToPattern(contractsDirectory);
|
||||
includedAntPattern = "**/";
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No group & artifact in path");
|
||||
}
|
||||
pattern = groupArtifactToPattern(contractsDirectory);
|
||||
includedAntPattern = wrapWithAntPattern(slashSeparatedGroupId() + "/" + this.projectArtifactId);
|
||||
includedAntPattern = wrapWithAntPattern(
|
||||
slashSeparatedGroupId() + "/" + this.projectArtifactId);
|
||||
}
|
||||
}
|
||||
log.info("Pattern to pick contracts equals [" + pattern + "]");
|
||||
@@ -120,13 +128,11 @@ public class ContractDownloader {
|
||||
}
|
||||
|
||||
private boolean hasVersionInPath(File file) {
|
||||
return file.getAbsolutePath()
|
||||
.contains(this.projectVersion);
|
||||
return file.getAbsolutePath().contains(this.projectVersion);
|
||||
}
|
||||
|
||||
private boolean hasSeparatedGroupInPath(File file, String separator) {
|
||||
return file.getAbsolutePath()
|
||||
.contains(groupAndArtifact(separator));
|
||||
return file.getAbsolutePath().contains(groupAndArtifact(separator));
|
||||
}
|
||||
|
||||
private String groupAndArtifact(String separator) {
|
||||
@@ -134,9 +140,9 @@ public class ContractDownloader {
|
||||
}
|
||||
|
||||
private String patternFromProperty(File contractsDirectory) {
|
||||
return ("^" + contractsDirectory.getAbsolutePath() +
|
||||
"(" + File.separator + ")?" + ".*" +
|
||||
contractsPath().replace("/", File.separator) + ".*$").replace("\\", "\\\\");
|
||||
return ("^" + contractsDirectory.getAbsolutePath() + "(" + File.separator + ")?"
|
||||
+ ".*" + contractsPath().replace("/", File.separator) + ".*$")
|
||||
.replace("\\", "\\\\");
|
||||
}
|
||||
|
||||
private String contractsPath() {
|
||||
@@ -144,18 +150,21 @@ public class ContractDownloader {
|
||||
}
|
||||
|
||||
private String surroundWithSeparator(String string) {
|
||||
String path = string.startsWith(File.separator) ? string : File.separator + string;
|
||||
String path = string.startsWith(File.separator) ? string
|
||||
: File.separator + string;
|
||||
return path.endsWith(File.separator) ? path : path + File.separator;
|
||||
}
|
||||
|
||||
private String wrapWithAntPattern(String path) {
|
||||
String changedPath = path.replace(File.separator, "/");
|
||||
return "**" + surroundWithSeparator(changedPath).replace(File.separator, "/") + "**/";
|
||||
return "**" + surroundWithSeparator(changedPath).replace(File.separator, "/")
|
||||
+ "**/";
|
||||
}
|
||||
|
||||
private File unpackAndDownloadContracts() {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will download contracts for [" + this.contractsJarStubConfiguration + "]");
|
||||
log.debug("Will download contracts for [" + this.contractsJarStubConfiguration
|
||||
+ "]");
|
||||
}
|
||||
Map.Entry<StubConfiguration, File> unpackedContractStubs = this.stubDownloader
|
||||
.downloadAndUnpackStubJar(this.contractsJarStubConfiguration);
|
||||
@@ -166,23 +175,17 @@ public class ContractDownloader {
|
||||
}
|
||||
|
||||
private String groupArtifactToPattern(File contractsDirectory) {
|
||||
return ("^" +
|
||||
contractsDirectory.getAbsolutePath() +
|
||||
"(" + File.separator + ")?" + ".*" +
|
||||
slashSeparatedGroupId() +
|
||||
File.separator +
|
||||
this.projectArtifactId
|
||||
+ File.separator +
|
||||
".*$").replace("\\", "\\\\");
|
||||
return ("^" + contractsDirectory.getAbsolutePath() + "(" + File.separator + ")?"
|
||||
+ ".*" + slashSeparatedGroupId() + File.separator + this.projectArtifactId
|
||||
+ File.separator + ".*$").replace("\\", "\\\\");
|
||||
}
|
||||
|
||||
private String fileToPattern(File contractsDirectory) {
|
||||
return ("^" +
|
||||
contractsDirectory.getAbsolutePath() +
|
||||
".*$").replace("\\", "\\\\");
|
||||
return ("^" + contractsDirectory.getAbsolutePath() + ".*$").replace("\\", "\\\\");
|
||||
}
|
||||
|
||||
private String slashSeparatedGroupId() {
|
||||
return this.projectGroupId.replace(".", File.separator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,14 +39,20 @@ public class ContractProjectUpdater {
|
||||
private static final Log log = LogFactory.getLog(ContractProjectUpdater.class);
|
||||
|
||||
private static final int DEFAULT_ATTEMPTS_NO = 10;
|
||||
|
||||
private static final long DEFAULT_WAIT_BETWEEN_ATTEMPTS = 1000;
|
||||
|
||||
// TODO: Add this to the documentation
|
||||
private static final String DEFAULT_COMMIT_MESSAGE = "Updating project [$project] with stubs";
|
||||
|
||||
private static final String GIT_ATTEMPTS_NO_PROP = "git.no-of-attempts";
|
||||
|
||||
private static final String GIT_WAIT_BETWEEN_ATTEMPTS = "git.wait-between-attempts";
|
||||
|
||||
private static final String GIT_COMMIT_MESSAGE = "git.commit-message";
|
||||
|
||||
private final StubRunnerOptions stubRunnerOptions;
|
||||
|
||||
private final GitContractsRepo gitContractsRepo;
|
||||
|
||||
public ContractProjectUpdater(StubRunnerOptions stubRunnerOptions) {
|
||||
@@ -66,40 +72,47 @@ public class ContractProjectUpdater {
|
||||
this.stubRunnerOptions.stubRepositoryRoot, this.stubRunnerOptions);
|
||||
copyStubs(projectName, rootStubsFolder, clonedRepo);
|
||||
GitRepo gitRepo = new GitRepo(clonedRepo, properties);
|
||||
String msg = StubRunnerPropertyUtils.getProperty(this.stubRunnerOptions.getProperties(),
|
||||
GIT_COMMIT_MESSAGE);
|
||||
GitRepo.CommitResult commit = gitRepo
|
||||
.commit(clonedRepo, commitMessage(projectName, msg));
|
||||
String msg = StubRunnerPropertyUtils
|
||||
.getProperty(this.stubRunnerOptions.getProperties(), GIT_COMMIT_MESSAGE);
|
||||
GitRepo.CommitResult commit = gitRepo.commit(clonedRepo,
|
||||
commitMessage(projectName, msg));
|
||||
if (commit == GitRepo.CommitResult.EMPTY) {
|
||||
log.info("There were no changes to commit. Won't push the changes");
|
||||
return;
|
||||
}
|
||||
String attempts = StubRunnerPropertyUtils.getProperty(this.stubRunnerOptions.getProperties(),
|
||||
GIT_ATTEMPTS_NO_PROP);
|
||||
int intAttempts = StringUtils.hasText(attempts) ? Integer.parseInt(attempts) : DEFAULT_ATTEMPTS_NO;
|
||||
String wait = StubRunnerPropertyUtils.getProperty(this.stubRunnerOptions.getProperties(),
|
||||
GIT_WAIT_BETWEEN_ATTEMPTS);
|
||||
long longWait = StringUtils.hasText(wait) ? Long.parseLong(wait) : DEFAULT_WAIT_BETWEEN_ATTEMPTS;
|
||||
String attempts = StubRunnerPropertyUtils.getProperty(
|
||||
this.stubRunnerOptions.getProperties(), GIT_ATTEMPTS_NO_PROP);
|
||||
int intAttempts = StringUtils.hasText(attempts) ? Integer.parseInt(attempts)
|
||||
: DEFAULT_ATTEMPTS_NO;
|
||||
String wait = StubRunnerPropertyUtils.getProperty(
|
||||
this.stubRunnerOptions.getProperties(), GIT_WAIT_BETWEEN_ATTEMPTS);
|
||||
long longWait = StringUtils.hasText(wait) ? Long.parseLong(wait)
|
||||
: DEFAULT_WAIT_BETWEEN_ATTEMPTS;
|
||||
tryToPushCurrentBranch(clonedRepo, gitRepo, intAttempts, longWait);
|
||||
}
|
||||
|
||||
private void tryToPushCurrentBranch(File clonedRepo, GitRepo gitRepo, int intAttempts,
|
||||
long longWait) {
|
||||
int currentAttempt = 0;
|
||||
while(currentAttempt < intAttempts) {
|
||||
log.info("Trying to push changes, attempt " + (currentAttempt + 1) + "/" + intAttempts);
|
||||
while (currentAttempt < intAttempts) {
|
||||
log.info("Trying to push changes, attempt " + (currentAttempt + 1) + "/"
|
||||
+ intAttempts);
|
||||
gitRepo.pull(clonedRepo);
|
||||
log.info("Successfully pulled changes from remote for project with contract and stubs");
|
||||
log.info(
|
||||
"Successfully pulled changes from remote for project with contract and stubs");
|
||||
try {
|
||||
gitRepo.pushCurrentBranch(clonedRepo);
|
||||
log.info("Successfully pushed changes with current stubs");
|
||||
break;
|
||||
} catch (IllegalStateException e) {
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
// empty
|
||||
log.error("Exception occurred while trying to push the changes", e);
|
||||
currentAttempt++;
|
||||
if (currentAttempt == intAttempts) {
|
||||
throw new IllegalStateException("Failed to push changes to the project with contracts and stubs. Exceeded number of retries [" + intAttempts + "]");
|
||||
throw new IllegalStateException(
|
||||
"Failed to push changes to the project with contracts and stubs. Exceeded number of retries ["
|
||||
+ intAttempts + "]");
|
||||
}
|
||||
try {
|
||||
Thread.sleep(longWait);
|
||||
@@ -112,9 +125,8 @@ public class ContractProjectUpdater {
|
||||
}
|
||||
|
||||
private String commitMessage(String projectName, String msg) {
|
||||
return StringUtils.hasText(msg) ?
|
||||
replaceProject(projectName, msg) :
|
||||
replaceProject(projectName, DEFAULT_COMMIT_MESSAGE);
|
||||
return StringUtils.hasText(msg) ? replaceProject(projectName, msg)
|
||||
: replaceProject(projectName, DEFAULT_COMMIT_MESSAGE);
|
||||
}
|
||||
|
||||
private String replaceProject(String projectName, String msg) {
|
||||
@@ -124,36 +136,44 @@ public class ContractProjectUpdater {
|
||||
private void copyStubs(String projectName, Path rootStubsFolder, File clonedRepo) {
|
||||
try {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Copying stubs from [" + rootStubsFolder.toString() + "] to the cloned repo [" + clonedRepo.getAbsolutePath() + "] for project [" + projectName + "]");
|
||||
log.debug("Copying stubs from [" + rootStubsFolder.toString()
|
||||
+ "] to the cloned repo [" + clonedRepo.getAbsolutePath()
|
||||
+ "] for project [" + projectName + "]");
|
||||
}
|
||||
Files.walkFileTree(rootStubsFolder,
|
||||
new DirectoryCopyingVisitor(rootStubsFolder, clonedRepo.toPath()));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Successfully copied stubs to the cloned repo for project [" + projectName + "]");
|
||||
log.debug("Successfully copied stubs to the cloned repo for project ["
|
||||
+ projectName + "]");
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DirectoryCopyingVisitor extends SimpleFileVisitor<Path> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(DirectoryCopyingVisitor.class);
|
||||
|
||||
private final Path from;
|
||||
|
||||
private final Path to;
|
||||
|
||||
DirectoryCopyingVisitor(Path from, Path to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will copy from [" + from.toString() + "] to [" + to.toString() + "]");
|
||||
log.debug("Will copy from [" + from.toString() + "] to [" + to.toString()
|
||||
+ "]");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
Path relativePath = this.from.relativize(dir);
|
||||
if (".git".equals(relativePath.toString())) {
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
@@ -164,7 +184,8 @@ class DirectoryCopyingVisitor extends SimpleFileVisitor<Path> {
|
||||
log.debug("Created a folder [" + targetPath.toString() + "]");
|
||||
}
|
||||
Files.createDirectory(targetPath);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Folder [" + targetPath.toString() + "] already exists");
|
||||
}
|
||||
@@ -173,12 +194,15 @@ class DirectoryCopyingVisitor extends SimpleFileVisitor<Path> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
Path relativePath = this.to.resolve(this.from.relativize(file));
|
||||
Files.copy(file, relativePath, StandardCopyOption.REPLACE_EXISTING);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Copied file from [" + file.toString() + "] to [" + relativePath.toString() + "]");
|
||||
log.debug("Copied file from [" + file.toString() + "] to ["
|
||||
+ relativePath.toString() + "]");
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
* Abstraction over a Git repo. Can cloned repo from a given location
|
||||
* and check its branch.
|
||||
* Abstraction over a Git repo. Can cloned repo from a given location and check its
|
||||
* branch.
|
||||
*
|
||||
* taken from: https://github.com/spring-cloud/spring-cloud-release-tools
|
||||
*
|
||||
@@ -101,7 +101,7 @@ class GitRepo {
|
||||
*/
|
||||
File cloneProject(URI projectUri) {
|
||||
try {
|
||||
log.info("Cloning repo from [" + projectUri + "] to [" + this.basedir + "]");
|
||||
log.info("Cloning repo from [" + projectUri + "] to [" + this.basedir + "]");
|
||||
Git git = cloneToBasedir(projectUri, this.basedir);
|
||||
if (git != null) {
|
||||
git.close();
|
||||
@@ -158,29 +158,34 @@ class GitRepo {
|
||||
* @param message - commit message
|
||||
*/
|
||||
CommitResult commit(File project, String message) {
|
||||
try(Git git = this.gitFactory.open(file(project))) {
|
||||
try (Git git = this.gitFactory.open(file(project))) {
|
||||
git.add().addFilepattern(".").call();
|
||||
git.commit().setAllowEmpty(false).setMessage(message).call();
|
||||
log.info("Commited successfully with message [" + message + "]");
|
||||
return CommitResult.SUCCESSFUL;
|
||||
} catch (EmtpyCommitException e) {
|
||||
}
|
||||
catch (EmtpyCommitException e) {
|
||||
log.info("There were no changes detected. Will not commit an empty commit");
|
||||
return CommitResult.EMPTY;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
void reset(File project) {
|
||||
try(Git git = this.gitFactory.open(file(project))) {
|
||||
try (Git git = this.gitFactory.open(file(project))) {
|
||||
git.reset().setMode(ResetCommand.ResetType.HARD).call();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
enum CommitResult {
|
||||
|
||||
SUCCESSFUL, EMPTY
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,9 +193,10 @@ class GitRepo {
|
||||
* @param project - Git project
|
||||
*/
|
||||
void pushCurrentBranch(File project) {
|
||||
try(Git git = this.gitFactory.open(file(project))) {
|
||||
try (Git git = this.gitFactory.open(file(project))) {
|
||||
this.gitFactory.push(git).call();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
@@ -223,8 +229,7 @@ class GitRepo {
|
||||
}
|
||||
}
|
||||
|
||||
private Ref checkoutBranch(File projectDir, String branch)
|
||||
throws GitAPIException {
|
||||
private Ref checkoutBranch(File projectDir, String branch) throws GitAPIException {
|
||||
Git git = this.gitFactory.open(projectDir);
|
||||
CheckoutCommand command = git.checkout().setName(branch);
|
||||
try {
|
||||
@@ -236,7 +241,8 @@ class GitRepo {
|
||||
catch (GitAPIException e) {
|
||||
deleteBaseDirIfExists();
|
||||
throw e;
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
git.close();
|
||||
}
|
||||
}
|
||||
@@ -272,8 +278,8 @@ class GitRepo {
|
||||
return containsBranch(git, label, null);
|
||||
}
|
||||
|
||||
private boolean containsBranch(Git git, String label, ListBranchCommand.ListMode listMode)
|
||||
throws GitAPIException {
|
||||
private boolean containsBranch(Git git, String label,
|
||||
ListBranchCommand.ListMode listMode) throws GitAPIException {
|
||||
ListBranchCommand command = git.branchList();
|
||||
if (listMode != null) {
|
||||
command.setListMode(listMode);
|
||||
@@ -299,35 +305,42 @@ class GitRepo {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the static method calls to {@link Git} and
|
||||
* {@link CloneCommand} allowing for easier unit testing.
|
||||
* Wraps the static method calls to {@link Git} and {@link CloneCommand} allowing for
|
||||
* easier unit testing.
|
||||
*/
|
||||
static class JGitFactory {
|
||||
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final JschConfigSessionFactory factory = new JschConfigSessionFactory() {
|
||||
|
||||
@Override protected void configure(OpenSshConfig.Host host, Session session) {
|
||||
@Override
|
||||
protected void configure(OpenSshConfig.Host host, Session session) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSch createDefaultJSch(FS fs) throws JSchException {
|
||||
Connector connector = null;
|
||||
try {
|
||||
if(SSHAgentConnector.isConnectorAvailable()){
|
||||
if (SSHAgentConnector.isConnectorAvailable()) {
|
||||
USocketFactory usf = new JNAUSocketFactory();
|
||||
connector = new SSHAgentConnector(usf);
|
||||
}
|
||||
log.info("Successfully connected to an agent");
|
||||
} catch (AgentProxyException e) {
|
||||
log.error("Exception occurred while trying to connect to agent. Will create"
|
||||
+ "the default JSch connection", e);
|
||||
}
|
||||
catch (AgentProxyException e) {
|
||||
log.error(
|
||||
"Exception occurred while trying to connect to agent. Will create"
|
||||
+ "the default JSch connection",
|
||||
e);
|
||||
return super.createDefaultJSch(fs);
|
||||
}
|
||||
final JSch jsch = super.createDefaultJSch(fs);
|
||||
if (connector != null) {
|
||||
JSch.setConfig("PreferredAuthentications", "publickey,password");
|
||||
IdentityRepository identityRepository = new RemoteIdentityRepository(connector);
|
||||
IdentityRepository identityRepository = new RemoteIdentityRepository(
|
||||
connector);
|
||||
jsch.setIdentityRepository(identityRepository);
|
||||
}
|
||||
return jsch;
|
||||
@@ -338,9 +351,11 @@ class GitRepo {
|
||||
|
||||
JGitFactory(GitStubDownloaderProperties properties) {
|
||||
if (org.springframework.util.StringUtils.hasText(properties.username)) {
|
||||
log.info("Passed username and password - will set a custom credentials provider");
|
||||
log.info(
|
||||
"Passed username and password - will set a custom credentials provider");
|
||||
this.provider = credentialsProvider(properties);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No custom credentials provider will be set");
|
||||
}
|
||||
@@ -349,8 +364,7 @@ class GitRepo {
|
||||
}
|
||||
|
||||
CredentialsProvider credentialsProvider(GitStubDownloaderProperties properties) {
|
||||
return new UsernamePasswordCredentialsProvider(
|
||||
properties.username,
|
||||
return new UsernamePasswordCredentialsProvider(properties.username,
|
||||
properties.password);
|
||||
}
|
||||
|
||||
@@ -367,20 +381,17 @@ class GitRepo {
|
||||
};
|
||||
|
||||
CloneCommand getCloneCommandByCloneRepository() {
|
||||
return Git.cloneRepository()
|
||||
.setCredentialsProvider(this.provider)
|
||||
return Git.cloneRepository().setCredentialsProvider(this.provider)
|
||||
.setTransportConfigCallback(this.callback);
|
||||
}
|
||||
|
||||
PushCommand push(Git git) {
|
||||
return git.push()
|
||||
.setCredentialsProvider(this.provider)
|
||||
return git.push().setCredentialsProvider(this.provider)
|
||||
.setTransportConfigCallback(this.callback);
|
||||
}
|
||||
|
||||
PullCommand pull(Git git) {
|
||||
return git.pull()
|
||||
.setCredentialsProvider(this.provider)
|
||||
return git.pull().setCredentialsProvider(this.provider)
|
||||
.setTransportConfigCallback(this.callback);
|
||||
}
|
||||
|
||||
@@ -392,5 +403,7 @@ class GitRepo {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.Collection;
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public interface HttpServerStub {
|
||||
|
||||
/**
|
||||
* Port on which the server is running
|
||||
*/
|
||||
@@ -21,14 +22,12 @@ public interface HttpServerStub {
|
||||
boolean isRunning();
|
||||
|
||||
/**
|
||||
* Starts the server on a random port. Should return itself
|
||||
* to allow chaining.
|
||||
* Starts the server on a random port. Should return itself to allow chaining.
|
||||
*/
|
||||
HttpServerStub start();
|
||||
|
||||
/**
|
||||
* Starts the server on a given port. Should return itself
|
||||
* to allow chaining.
|
||||
* Starts the server on a given port. Should return itself to allow chaining.
|
||||
*/
|
||||
HttpServerStub start(int port);
|
||||
|
||||
@@ -38,8 +37,8 @@ public interface HttpServerStub {
|
||||
HttpServerStub stop();
|
||||
|
||||
/**
|
||||
* Registers the stub files in the HTTP server stub. Should return itself
|
||||
* to allow chaining.
|
||||
* Registers the stub files in the HTTP server stub. Should return itself to allow
|
||||
* chaining.
|
||||
*/
|
||||
HttpServerStub registerMappings(Collection<File> stubFiles);
|
||||
|
||||
@@ -52,4 +51,5 @@ public interface HttpServerStub {
|
||||
* Returns {@code true} if the file is a valid stub mapping
|
||||
*/
|
||||
boolean isAccepted(File file);
|
||||
|
||||
}
|
||||
|
||||
@@ -23,4 +23,5 @@ package org.springframework.cloud.contract.stubrunner;
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
class MessageNotMatchingException extends RuntimeException {
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.Collection;
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class NoOpHttpServerStub implements HttpServerStub {
|
||||
|
||||
@Override
|
||||
public int port() {
|
||||
return -1;
|
||||
@@ -37,11 +38,14 @@ class NoOpHttpServerStub implements HttpServerStub {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public String registeredMappings() {
|
||||
@Override
|
||||
public String registeredMappings() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override public boolean isAccepted(File file) {
|
||||
@Override
|
||||
public boolean isAccepted(File file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
/**
|
||||
* Uses {@code META-INF/spring.factories} to read {@link ProtocolResolver} list
|
||||
* that gets added to {@link DefaultResourceLoader}. Each implementor of a new
|
||||
* {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}, if
|
||||
* one uses a new protocol, should register their own {@link ProtocolResolver} so
|
||||
* that Stub Runner can convert a {@link String} version of a URI to a {@link Resource}.
|
||||
* Uses {@code META-INF/spring.factories} to read {@link ProtocolResolver} list that gets
|
||||
* added to {@link DefaultResourceLoader}. Each implementor of a new
|
||||
* {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}, if one
|
||||
* uses a new protocol, should register their own {@link ProtocolResolver} so that Stub
|
||||
* Runner can convert a {@link String} version of a URI to a {@link Resource}.
|
||||
*
|
||||
* IMPORTANT! Internal tool. Do not use.
|
||||
*
|
||||
@@ -41,14 +41,16 @@ import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
public class ResourceResolver {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ResourceResolver.class);
|
||||
|
||||
private static final List<ProtocolResolver> RESOLVERS = new ArrayList<>();
|
||||
|
||||
private static final DefaultResourceLoader LOADER = new DefaultResourceLoader();
|
||||
|
||||
static {
|
||||
RESOLVERS.addAll(
|
||||
SpringFactoriesLoader.loadFactories(StubDownloaderBuilder.class, null)
|
||||
);
|
||||
RESOLVERS.addAll(new StubDownloaderBuilderProvider().defaultStubDownloaderBuilders());
|
||||
SpringFactoriesLoader.loadFactories(StubDownloaderBuilder.class, null));
|
||||
RESOLVERS.addAll(
|
||||
new StubDownloaderBuilderProvider().defaultStubDownloaderBuilders());
|
||||
for (ProtocolResolver resolver : RESOLVERS) {
|
||||
LOADER.addProtocolResolver(resolver);
|
||||
}
|
||||
@@ -61,9 +63,13 @@ public class ResourceResolver {
|
||||
public static Resource resource(String url) {
|
||||
try {
|
||||
return LOADER.getResource(url);
|
||||
} catch (Exception e) {
|
||||
log.error("Exception occurred while trying to read the resource [" + url + "]", e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(
|
||||
"Exception occurred while trying to read the resource [" + url + "]",
|
||||
e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -60,9 +60,10 @@ public final class ScmStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
return ACCEPTABLE_PROTOCOLS.stream().anyMatch(url::startsWith);
|
||||
}
|
||||
|
||||
@Override public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
if (stubRunnerOptions.getStubsMode() == StubRunnerProperties.StubsMode.CLASSPATH ||
|
||||
stubRunnerOptions.getStubRepositoryRoot() == null) {
|
||||
@Override
|
||||
public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
if (stubRunnerOptions.getStubsMode() == StubRunnerProperties.StubsMode.CLASSPATH
|
||||
|| stubRunnerOptions.getStubRepositoryRoot() == null) {
|
||||
return null;
|
||||
}
|
||||
Resource resource = stubRunnerOptions.getStubRepositoryRoot();
|
||||
@@ -72,14 +73,15 @@ public final class ScmStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
return new GitStubDownloader(stubRunnerOptions);
|
||||
}
|
||||
|
||||
@Override public Resource resolve(String location, ResourceLoader resourceLoader) {
|
||||
@Override
|
||||
public Resource resolve(String location, ResourceLoader resourceLoader) {
|
||||
if (StringUtils.isEmpty(location) || !isProtocolAccepted(location)) {
|
||||
return null;
|
||||
}
|
||||
return new GitResource(location);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Primitive version of a Git {@link Resource}
|
||||
@@ -92,17 +94,21 @@ class GitResource extends AbstractResource {
|
||||
this.rawLocation = location;
|
||||
}
|
||||
|
||||
@Override public String getDescription() {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return this.rawLocation;
|
||||
}
|
||||
|
||||
@Override public InputStream getInputStream() throws IOException {
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public URI getURI() throws IOException {
|
||||
@Override
|
||||
public URI getURI() throws IOException {
|
||||
return URI.create(this.rawLocation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GitContractsRepo {
|
||||
@@ -120,34 +126,43 @@ class GitContractsRepo {
|
||||
|
||||
File clonedRepo(Resource repo) {
|
||||
File file = CACHED_LOCATIONS.get(repo);
|
||||
GitStubDownloaderProperties properties = new GitStubDownloaderProperties(repo, this.options);
|
||||
GitStubDownloaderProperties properties = new GitStubDownloaderProperties(repo,
|
||||
this.options);
|
||||
if (file == null) {
|
||||
File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage.createTempDir(TEMP_DIR_PREFIX);
|
||||
File tmpDirWhereStubsWillBeUnzipped = TemporaryFileStorage
|
||||
.createTempDir(TEMP_DIR_PREFIX);
|
||||
GitRepo gitRepo = new GitRepo(tmpDirWhereStubsWillBeUnzipped, properties);
|
||||
file = gitRepo.cloneProject(properties.url);
|
||||
gitRepo.checkout(file, properties.branch);
|
||||
CACHED_LOCATIONS.put(repo, file);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("The project hasn't already been cloned. Cloned it to [" + file + "]");
|
||||
log.debug("The project hasn't already been cloned. Cloned it to [" + file
|
||||
+ "]");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("The project has already been cloned to [" + file + "]. Will reset any changes.");
|
||||
log.debug("The project has already been cloned to [" + file
|
||||
+ "]. Will reset any changes.");
|
||||
}
|
||||
new GitRepo(file, properties).reset(file);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GitStubDownloader implements StubDownloader {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GitStubDownloader.class);
|
||||
|
||||
// Preloading class for the shutdown hook not to throw ClassNotFound
|
||||
private static final Class CLAZZ = TemporaryFileStorage.class;
|
||||
|
||||
private final StubRunnerOptions stubRunnerOptions;
|
||||
|
||||
private final boolean deleteStubsAfterTest;
|
||||
|
||||
private final GitContractsRepo gitContractsRepo;
|
||||
|
||||
GitStubDownloader(StubRunnerOptions stubRunnerOptions) {
|
||||
@@ -157,48 +172,62 @@ class GitStubDownloader implements StubDownloader {
|
||||
registerShutdownHook();
|
||||
}
|
||||
|
||||
@Override public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
@Override
|
||||
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
StubConfiguration stubConfiguration) {
|
||||
if (StringUtils.isEmpty(stubConfiguration.version) || "+".equals(stubConfiguration.version)) {
|
||||
throw new IllegalStateException("Concrete version wasn't passed for [" + stubConfiguration.toColonSeparatedDependencyNotation() + "]");
|
||||
if (StringUtils.isEmpty(stubConfiguration.version)
|
||||
|| "+".equals(stubConfiguration.version)) {
|
||||
throw new IllegalStateException("Concrete version wasn't passed for ["
|
||||
+ stubConfiguration.toColonSeparatedDependencyNotation() + "]");
|
||||
}
|
||||
try {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Trying to find a contract for [" + stubConfiguration.toColonSeparatedDependencyNotation() + "]");
|
||||
log.debug("Trying to find a contract for ["
|
||||
+ stubConfiguration.toColonSeparatedDependencyNotation() + "]");
|
||||
}
|
||||
Resource repo = this.stubRunnerOptions.getStubRepositoryRoot();
|
||||
File clonedRepo = this.gitContractsRepo.clonedRepo(repo);
|
||||
FileWalker walker = new FileWalker(stubConfiguration);
|
||||
Files.walkFileTree(clonedRepo.toPath(), walker);
|
||||
if (walker.foundFile != null) {
|
||||
return new AbstractMap.SimpleEntry<>(stubConfiguration, walker.foundFile.toFile());
|
||||
return new AbstractMap.SimpleEntry<>(stubConfiguration,
|
||||
walker.foundFile.toFile());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No matching contracts were found in the repo for [" + stubConfiguration.toColonSeparatedDependencyNotation() + "]. Returning null");
|
||||
log.debug("No matching contracts were found in the repo for ["
|
||||
+ stubConfiguration.toColonSeparatedDependencyNotation()
|
||||
+ "]. Returning null");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerShutdownHook() {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(
|
||||
() -> TemporaryFileStorage.cleanup(GitStubDownloader.this.deleteStubsAfterTest)));
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> TemporaryFileStorage
|
||||
.cleanup(GitStubDownloader.this.deleteStubsAfterTest)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GitStubDownloaderProperties {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GitStubDownloaderProperties.class);
|
||||
|
||||
private static final String GIT_BRANCH_PROPERTY = "git.branch";
|
||||
|
||||
private static final String GIT_USERNAME_PROPERTY = "git.username";
|
||||
|
||||
private static final String GIT_PASSWORD_PROPERTY = "git.password";
|
||||
|
||||
final URI url;
|
||||
|
||||
final String username;
|
||||
|
||||
final String password;
|
||||
|
||||
final String branch;
|
||||
|
||||
GitStubDownloaderProperties(Resource repo, StubRunnerOptions options) {
|
||||
@@ -206,24 +235,28 @@ class GitStubDownloaderProperties {
|
||||
Map<String, String> args = options.getProperties();
|
||||
try {
|
||||
repoUrl = schemeSpecificPart(repo.getURI());
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
// if we had git://https://... we want the part starting from https
|
||||
// if we had git://git@... we want the full address again
|
||||
// if the URL starts with git@... and ends with .git, we want to remove it
|
||||
String modifiedRepo = repoUrl.startsWith("git@") ? modifyUrlForGitRepo(repoUrl) : repoUrl;
|
||||
String modifiedRepo = repoUrl.startsWith("git@") ? modifyUrlForGitRepo(repoUrl)
|
||||
: repoUrl;
|
||||
this.url = URI.create(modifiedRepo);
|
||||
String username = StubRunnerPropertyUtils.getProperty(args, GIT_USERNAME_PROPERTY);
|
||||
String username = StubRunnerPropertyUtils.getProperty(args,
|
||||
GIT_USERNAME_PROPERTY);
|
||||
this.username = StringUtils.hasText(username) ? username : options.getUsername();
|
||||
String password = StubRunnerPropertyUtils.getProperty(args, GIT_PASSWORD_PROPERTY);
|
||||
String password = StubRunnerPropertyUtils.getProperty(args,
|
||||
GIT_PASSWORD_PROPERTY);
|
||||
this.password = StringUtils.hasText(password) ? password : options.getPassword();
|
||||
String branch = StubRunnerPropertyUtils.getProperty(args, GIT_BRANCH_PROPERTY);
|
||||
this.branch = StringUtils.hasText(branch) ? branch : "master";
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Repo url is [" + repoUrl + "], modified url string "
|
||||
+ "is [" + modifiedRepo + "] URL is [" + this.url + "] and "
|
||||
+ "branch is [" + this.branch + "]");
|
||||
log.debug("Repo url is [" + repoUrl + "], modified url string " + "is ["
|
||||
+ modifiedRepo + "] URL is [" + this.url + "] and " + "branch is ["
|
||||
+ this.branch + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,12 +271,15 @@ class GitStubDownloaderProperties {
|
||||
private String modifyUrlForGitRepo(String gitRepo) {
|
||||
return "git:" + gitRepo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FileWalker extends SimpleFileVisitor<Path> {
|
||||
|
||||
private final PathMatcher matcherWithDot;
|
||||
|
||||
private final PathMatcher matcherWithoutDot;
|
||||
|
||||
Path foundFile;
|
||||
|
||||
FileWalker(StubConfiguration stubConfiguration) {
|
||||
@@ -253,20 +289,21 @@ class FileWalker extends SimpleFileVisitor<Path> {
|
||||
.getPathMatcher("glob:" + matcherGlob(stubConfiguration, "/"));
|
||||
}
|
||||
|
||||
private String matcherGlob(StubConfiguration stubConfiguration, String groupArtifactSeparator) {
|
||||
private String matcherGlob(StubConfiguration stubConfiguration,
|
||||
String groupArtifactSeparator) {
|
||||
return "**" + stubConfiguration.groupId + groupArtifactSeparator
|
||||
+ stubConfiguration.artifactId + "/"
|
||||
+ stubConfiguration.version;
|
||||
+ stubConfiguration.artifactId + "/" + stubConfiguration.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
if (this.matcherWithDot.matches(dir.toAbsolutePath()) ||
|
||||
this.matcherWithoutDot.matches(dir.toAbsolutePath())) {
|
||||
if (this.matcherWithDot.matches(dir.toAbsolutePath())
|
||||
|| this.matcherWithoutDot.matches(dir.toAbsolutePath())) {
|
||||
this.foundFile = dir;
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,13 +23,18 @@ import org.springframework.util.StringUtils;
|
||||
* groupId:artifactId:version:classifier notation
|
||||
*/
|
||||
public class StubConfiguration {
|
||||
|
||||
private static final String STUB_COLON_DELIMITER = ":";
|
||||
static final String DEFAULT_VERSION = "+";
|
||||
|
||||
public static final String DEFAULT_CLASSIFIER = "stubs";
|
||||
|
||||
final String groupId;
|
||||
|
||||
final String artifactId;
|
||||
|
||||
final String version;
|
||||
|
||||
final String classifier;
|
||||
|
||||
public StubConfiguration(String groupId, String artifactId, String version) {
|
||||
@@ -87,18 +92,16 @@ public class StubConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a colon separated representation of the stub configuration
|
||||
* (e.g. groupid:artifactid:version:classifier)
|
||||
* Returns a colon separated representation of the stub configuration (e.g.
|
||||
* groupid:artifactid:version:classifier)
|
||||
*/
|
||||
public String toColonSeparatedDependencyNotation() {
|
||||
if (!isDefined()) {
|
||||
return "";
|
||||
}
|
||||
return StringUtils.arrayToDelimitedString(
|
||||
new String[] { nullCheck(this.groupId),
|
||||
nullCheck(this.artifactId),
|
||||
nullCheck(this.version),
|
||||
nullCheck(this.classifier) },
|
||||
new String[] { nullCheck(this.groupId), nullCheck(this.artifactId),
|
||||
nullCheck(this.version), nullCheck(this.classifier) },
|
||||
STUB_COLON_DELIMITER);
|
||||
}
|
||||
|
||||
@@ -108,10 +111,9 @@ public class StubConfiguration {
|
||||
|
||||
/**
|
||||
* Checks if ivy notation matches group and artifact ids
|
||||
*
|
||||
* @param ivyNotationAsString - e.g. group:artifact:version:classifier
|
||||
* @return {@code true} if artifact id matches and there's no group id. Or if
|
||||
* both group id and artifact id are present and matching
|
||||
* @return {@code true} if artifact id matches and there's no group id. Or if both
|
||||
* group id and artifact id are present and matching
|
||||
*/
|
||||
public boolean groupIdAndArtifactMatches(String ivyNotationAsString) {
|
||||
String[] parts = ivyNotationFrom(ivyNotationAsString);
|
||||
@@ -127,8 +129,8 @@ public class StubConfiguration {
|
||||
* Returns {@code true} for a snapshot or a LATEST (+) version
|
||||
*/
|
||||
public boolean isVersionChanging() {
|
||||
return DEFAULT_VERSION.equals(this.version) ||
|
||||
this.version.toLowerCase().contains("snapshot");
|
||||
return DEFAULT_VERSION.equals(this.version)
|
||||
|| this.version.toLowerCase().contains("snapshot");
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
@@ -151,7 +153,8 @@ public class StubConfiguration {
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.artifactId == null) ? 0 : this.artifactId.hashCode());
|
||||
result = prime * result
|
||||
+ ((this.artifactId == null) ? 0 : this.artifactId.hashCode());
|
||||
result = prime * result + ((this.groupId == null) ? 0 : this.groupId.hashCode());
|
||||
return result;
|
||||
}
|
||||
@@ -185,13 +188,16 @@ public class StubConfiguration {
|
||||
if (strings.length == 1) {
|
||||
return this.artifactId.equals(ivyNotationAsString);
|
||||
}
|
||||
if (strings.length >= 2 && !(this.groupId.equals(strings[0]) && this.artifactId.equals(strings[1]))) {
|
||||
if (strings.length >= 2 && !(this.groupId.equals(strings[0])
|
||||
&& this.artifactId.equals(strings[1]))) {
|
||||
return false;
|
||||
}
|
||||
if (strings.length >= 3 && !(this.version.equals(strings[2]) || DEFAULT_VERSION.equals(strings[2]))) {
|
||||
if (strings.length >= 3 && !(this.version.equals(strings[2])
|
||||
|| DEFAULT_VERSION.equals(strings[2]))) {
|
||||
return false;
|
||||
}
|
||||
if (strings.length == 4 && !(this.classifier.equals(strings[3]) || DEFAULT_CLASSIFIER.equals(strings[3]))) {
|
||||
if (strings.length == 4 && !(this.classifier.equals(strings[3])
|
||||
|| DEFAULT_CLASSIFIER.equals(strings[3]))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -210,4 +216,5 @@ public class StubConfiguration {
|
||||
public String toString() {
|
||||
return toColonSeparatedDependencyNotation();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,11 +20,11 @@ import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Contract for providing a tuple containing configuration of a downloaded
|
||||
* and unpacked stub, together with the file location of that extracted artifact.
|
||||
* Contract for providing a tuple containing configuration of a downloaded and unpacked
|
||||
* stub, together with the file location of that extracted artifact.
|
||||
*
|
||||
* Note: Actually the artifact doesn't have to be a JAR. method name contains
|
||||
* that suffix for historical reasons.
|
||||
* Note: Actually the artifact doesn't have to be a JAR. method name contains that suffix
|
||||
* for historical reasons.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.0
|
||||
@@ -32,8 +32,11 @@ import java.util.Map;
|
||||
public interface StubDownloader {
|
||||
|
||||
/**
|
||||
* Returns a mapping of updated StubConfiguration (it will contain the resolved version) and the location of the downloaded JAR.
|
||||
* If there was no artifact this method will return {@code null}.
|
||||
* Returns a mapping of updated StubConfiguration (it will contain the resolved
|
||||
* version) and the location of the downloaded JAR. If there was no artifact this
|
||||
* method will return {@code null}.
|
||||
*/
|
||||
Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(StubConfiguration stubConfiguration);
|
||||
Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
StubConfiguration stubConfiguration);
|
||||
|
||||
}
|
||||
@@ -21,14 +21,14 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* Builder for a {@link StubDownloader}. Can't allow direct usage
|
||||
* of {@link StubDownloader} cause in order to register instances
|
||||
* of this interface in {@link org.springframework.core.io.support.SpringFactoriesLoader}
|
||||
* one needs a default constructor whereas the {@link StubDownloader}
|
||||
* instances need to be constructed from stub related options.
|
||||
* Builder for a {@link StubDownloader}. Can't allow direct usage of
|
||||
* {@link StubDownloader} cause in order to register instances of this interface in
|
||||
* {@link org.springframework.core.io.support.SpringFactoriesLoader} one needs a default
|
||||
* constructor whereas the {@link StubDownloader} instances need to be constructed from
|
||||
* stub related options.
|
||||
*
|
||||
* Since {@code 2.0.0} extends {@link ProtocolResolver}. Implementations have
|
||||
* to tell Spring how to parse the repository root String into a resource.
|
||||
* Since {@code 2.0.0} extends {@link ProtocolResolver}. Implementations have to tell
|
||||
* Spring how to parse the repository root String into a resource.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.1.0
|
||||
@@ -36,11 +36,14 @@ import org.springframework.core.io.ResourceLoader;
|
||||
public interface StubDownloaderBuilder extends ProtocolResolver {
|
||||
|
||||
/**
|
||||
* @return {@link StubDownloader} instance of {@code null} if current parameters don't allow building the instance
|
||||
* @return {@link StubDownloader} instance of {@code null} if current parameters don't
|
||||
* allow building the instance
|
||||
*/
|
||||
StubDownloader build(StubRunnerOptions stubRunnerOptions);
|
||||
|
||||
@Override default Resource resolve(String location, ResourceLoader resourceLoader) {
|
||||
@Override
|
||||
default Resource resolve(String location, ResourceLoader resourceLoader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import java.util.List;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
/**
|
||||
* Provider for {@link StubDownloaderBuilder}. It can also pick a default
|
||||
* downloader if none is provided
|
||||
* Provider for {@link StubDownloaderBuilder}. It can also pick a default downloader if
|
||||
* none is provided
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.1.0
|
||||
@@ -28,8 +28,10 @@ public class StubDownloaderBuilderProvider {
|
||||
|
||||
/**
|
||||
* @param stubRunnerOptions
|
||||
* @param additionalBuilders - optional array of {@link StubDownloaderBuilder}s to append to the list of builders
|
||||
* @return composite {@link StubDownloader} that iterates over a list of stub downloaders
|
||||
* @param additionalBuilders - optional array of {@link StubDownloaderBuilder}s to
|
||||
* append to the list of builders
|
||||
* @return composite {@link StubDownloader} that iterates over a list of stub
|
||||
* downloaders
|
||||
*/
|
||||
public StubDownloader get(StubRunnerOptions stubRunnerOptions,
|
||||
StubDownloaderBuilder... additionalBuilders) {
|
||||
@@ -43,8 +45,8 @@ public class StubDownloaderBuilderProvider {
|
||||
}
|
||||
|
||||
List<StubDownloaderBuilder> defaultStubDownloaderBuilders() {
|
||||
return Arrays
|
||||
.asList(new ScmStubDownloaderBuilder(), new ClasspathStubProvider(),
|
||||
new AetherStubDownloaderBuilder());
|
||||
return Arrays.asList(new ScmStubDownloaderBuilder(), new ClasspathStubProvider(),
|
||||
new AetherStubDownloaderBuilder());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,19 +23,20 @@ import java.util.Map;
|
||||
import org.springframework.cloud.contract.spec.Contract;
|
||||
|
||||
public interface StubFinder extends StubTrigger {
|
||||
|
||||
/**
|
||||
* For the given groupId and artifactId tries to find the matching
|
||||
* URL of the running stub.
|
||||
*
|
||||
* @param groupId - might be null. In that case a search only via artifactId takes place
|
||||
* For the given groupId and artifactId tries to find the matching URL of the running
|
||||
* stub.
|
||||
* @param groupId - might be null. In that case a search only via artifactId takes
|
||||
* place
|
||||
* @return URL of a running stub or throws exception if not found
|
||||
*/
|
||||
URL findStubUrl(String groupId, String artifactId) throws StubNotFoundException;
|
||||
|
||||
/**
|
||||
* For the given Ivy notation {@code [groupId]:artifactId:[version]:[classifier]} tries to
|
||||
* find the matching URL of the running stub. You can also pass only {@code artifactId}.
|
||||
*
|
||||
* For the given Ivy notation {@code [groupId]:artifactId:[version]:[classifier]}
|
||||
* tries to find the matching URL of the running stub. You can also pass only
|
||||
* {@code artifactId}.
|
||||
* @param ivyNotation - Ivy representation of the Maven artifact
|
||||
* @return URL of a running stub or throws exception if not found
|
||||
*/
|
||||
@@ -50,4 +51,5 @@ public interface StubFinder extends StubTrigger {
|
||||
* Returns the list of Contracts
|
||||
*/
|
||||
Map<StubConfiguration, Collection<Contract>> getContracts();
|
||||
|
||||
}
|
||||
@@ -9,10 +9,12 @@ package org.springframework.cloud.contract.stubrunner;
|
||||
public class StubNotFoundException extends RuntimeException {
|
||||
|
||||
public StubNotFoundException(String groupId, String artifactId) {
|
||||
super("Stub not found for groupid [" + groupId + "] and artifactid [" + artifactId + "]");
|
||||
super("Stub not found for groupid [" + groupId + "] and artifactid [" + artifactId
|
||||
+ "]");
|
||||
}
|
||||
|
||||
public StubNotFoundException(String ivyNotation) {
|
||||
super("Stub not found for stub with notation [" + ivyNotation + "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,10 +46,15 @@ class StubRepository {
|
||||
private static final Log log = LogFactory.getLog(StubRepository.class);
|
||||
|
||||
private final File path;
|
||||
|
||||
final List<File> stubs;
|
||||
|
||||
final Collection<Contract> contracts;
|
||||
|
||||
private final List<ContractConverter> contractConverters;
|
||||
|
||||
private final List<HttpServerStub> httpServerStubs;
|
||||
|
||||
private final StubRunnerOptions options;
|
||||
|
||||
StubRepository(File repository, List<HttpServerStub> httpServerStubs,
|
||||
@@ -58,9 +63,11 @@ class StubRepository {
|
||||
throw new IllegalArgumentException(
|
||||
"Missing descriptor repository under path [" + repository + "]");
|
||||
}
|
||||
this.contractConverters = SpringFactoriesLoader.loadFactories(ContractConverter.class, null);
|
||||
this.contractConverters = SpringFactoriesLoader
|
||||
.loadFactories(ContractConverter.class, null);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Found the following contract converters " + this.contractConverters);
|
||||
log.trace(
|
||||
"Found the following contract converters " + this.contractConverters);
|
||||
}
|
||||
this.httpServerStubs = httpServerStubs;
|
||||
this.path = repository;
|
||||
@@ -107,8 +114,7 @@ class StubRepository {
|
||||
: Collections.<File>emptyList();
|
||||
}
|
||||
|
||||
private List<File> collectMappings(
|
||||
File descriptorsDirectory) {
|
||||
private List<File> collectMappings(File descriptorsDirectory) {
|
||||
final List<File> mappingDescriptors = new ArrayList<>();
|
||||
try {
|
||||
Files.walkFileTree(Paths.get(descriptorsDirectory.toURI()),
|
||||
@@ -117,7 +123,8 @@ class StubRepository {
|
||||
public FileVisitResult visitFile(Path path,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
File file = path.toFile();
|
||||
if (httpServerStubAccepts(file) && isStubPerConsumerPathMatching(file)) {
|
||||
if (httpServerStubAccepts(file)
|
||||
&& isStubPerConsumerPathMatching(file)) {
|
||||
mappingDescriptors.add(file);
|
||||
}
|
||||
return super.visitFile(path, attrs);
|
||||
@@ -155,7 +162,8 @@ class StubRepository {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Collection<Contract> collectContractDescriptors(final File descriptorsDirectory) {
|
||||
private Collection<Contract> collectContractDescriptors(
|
||||
final File descriptorsDirectory) {
|
||||
final List<Contract> contractDescriptors = new ArrayList<>();
|
||||
try {
|
||||
Files.walkFileTree(Paths.get(descriptorsDirectory.toURI()),
|
||||
@@ -168,11 +176,20 @@ class StubRepository {
|
||||
if (isStubPerConsumerPathMatching(file)) {
|
||||
if (isContractDescriptor(file)) {
|
||||
contractDescriptors
|
||||
.addAll(ContractVerifierDslConverter.convertAsCollection(file.getParentFile(), file));
|
||||
} else if (converter != null && converter.isAccepted(file)) {
|
||||
contractDescriptors.addAll(converter.convertFrom(file));
|
||||
} else if (YamlContractConverter.INSTANCE.isAccepted(file)) {
|
||||
contractDescriptors.addAll(YamlContractConverter.INSTANCE.convertFrom(file));
|
||||
.addAll(ContractVerifierDslConverter
|
||||
.convertAsCollection(
|
||||
file.getParentFile(), file));
|
||||
}
|
||||
else if (converter != null
|
||||
&& converter.isAccepted(file)) {
|
||||
contractDescriptors
|
||||
.addAll(converter.convertFrom(file));
|
||||
}
|
||||
else if (YamlContractConverter.INSTANCE
|
||||
.isAccepted(file)) {
|
||||
contractDescriptors
|
||||
.addAll(YamlContractConverter.INSTANCE
|
||||
.convertFrom(file));
|
||||
}
|
||||
}
|
||||
return super.visitFile(path, attrs);
|
||||
@@ -194,7 +211,9 @@ class StubRepository {
|
||||
String absolutePath = file.getAbsolutePath();
|
||||
boolean stubPerConsumerMatching = absolutePath.contains(searchedConsumerName);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Absolute path [" + absolutePath + "] contains [" + searchedConsumerName + "] in its path [" + stubPerConsumerMatching + "]");
|
||||
log.debug("Absolute path [" + absolutePath + "] contains ["
|
||||
+ searchedConsumerName + "] in its path [" + stubPerConsumerMatching
|
||||
+ "]");
|
||||
}
|
||||
return stubPerConsumerMatching;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,11 @@ public class StubRunner implements StubRunning {
|
||||
private static final Log log = LogFactory.getLog(StubRunner.class);
|
||||
|
||||
private final StubRepository stubRepository;
|
||||
|
||||
private final StubConfiguration stubsConfiguration;
|
||||
|
||||
private final StubRunnerOptions stubRunnerOptions;
|
||||
|
||||
private final StubRunnerExecutor localStubRunner;
|
||||
|
||||
public StubRunner(StubRunnerOptions stubRunnerOptions, String repositoryPath,
|
||||
@@ -59,31 +62,40 @@ public class StubRunner implements StubRunning {
|
||||
MessageVerifier<?> contractVerifierMessaging) {
|
||||
this.stubsConfiguration = stubsConfiguration;
|
||||
this.stubRunnerOptions = stubRunnerOptions;
|
||||
List<HttpServerStub> serverStubs = SpringFactoriesLoader.loadFactories(HttpServerStub.class, null);
|
||||
this.stubRepository = new StubRepository(new File(repositoryPath), serverStubs, this.stubRunnerOptions);
|
||||
List<HttpServerStub> serverStubs = SpringFactoriesLoader
|
||||
.loadFactories(HttpServerStub.class, null);
|
||||
this.stubRepository = new StubRepository(new File(repositoryPath), serverStubs,
|
||||
this.stubRunnerOptions);
|
||||
AvailablePortScanner portScanner = new AvailablePortScanner(
|
||||
stubRunnerOptions.getMinPortValue(), stubRunnerOptions.getMaxPortValue());
|
||||
this.localStubRunner = new StubRunnerExecutor(portScanner, contractVerifierMessaging, serverStubs);
|
||||
this.localStubRunner = new StubRunnerExecutor(portScanner,
|
||||
contractVerifierMessaging, serverStubs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunningStubs runStubs() {
|
||||
registerShutdownHook();
|
||||
RunningStubs stubs = this.localStubRunner.runStubs(this.stubRunnerOptions, this.stubRepository,
|
||||
this.stubsConfiguration);
|
||||
RunningStubs stubs = this.localStubRunner.runStubs(this.stubRunnerOptions,
|
||||
this.stubRepository, this.stubsConfiguration);
|
||||
if (this.stubRunnerOptions.hasMappingsOutputFolder()) {
|
||||
String registeredMappings = this.localStubRunner.registeredMappings();
|
||||
if (StringUtils.hasText(registeredMappings)) {
|
||||
File outputMappings = new File(this.stubRunnerOptions.getMappingsOutputFolder(),
|
||||
File outputMappings = new File(
|
||||
this.stubRunnerOptions.getMappingsOutputFolder(),
|
||||
this.stubsConfiguration.artifactId + "_"
|
||||
+ stubs.getPort(this.stubsConfiguration.toColonSeparatedDependencyNotation()));
|
||||
+ stubs.getPort(this.stubsConfiguration
|
||||
.toColonSeparatedDependencyNotation()));
|
||||
try {
|
||||
outputMappings.getParentFile().mkdirs();
|
||||
clearOldFiles(outputMappings.getParentFile(), this.stubsConfiguration.artifactId);
|
||||
clearOldFiles(outputMappings.getParentFile(),
|
||||
this.stubsConfiguration.artifactId);
|
||||
outputMappings.createNewFile();
|
||||
Files.write(Paths.get(outputMappings.toURI()), registeredMappings.getBytes());
|
||||
Files.write(Paths.get(outputMappings.toURI()),
|
||||
registeredMappings.getBytes());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Stored the mappings for artifactid [" + this.stubsConfiguration.artifactId + "] at [" + outputMappings + "] location");
|
||||
log.debug("Stored the mappings for artifactid ["
|
||||
+ this.stubsConfiguration.artifactId + "] at ["
|
||||
+ outputMappings + "] location");
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -97,20 +109,22 @@ public class StubRunner implements StubRunning {
|
||||
|
||||
private void clearOldFiles(File outputFolder, final String filename) {
|
||||
File[] files = outputFolder.listFiles(new FilenameFilter() {
|
||||
@Override public boolean accept(final File dir, final String name) {
|
||||
@Override
|
||||
public boolean accept(final File dir, final String name) {
|
||||
return name.startsWith(filename);
|
||||
}
|
||||
});
|
||||
if (files == null) {
|
||||
if(log.isDebugEnabled()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to retrieve any mappings");
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (final File file : files) {
|
||||
if (!file.delete()) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("Exception occurred while trying to remove [" + file.getAbsolutePath() + "]");
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Exception occurred while trying to remove ["
|
||||
+ file.getAbsolutePath() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,4 +190,5 @@ public class StubRunner implements StubRunning {
|
||||
this.localStubRunner.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,17 +51,23 @@ class StubRunnerExecutor implements StubFinder {
|
||||
static final Set<StubServer> STUB_SERVERS = new ConcurrentHashSet<>();
|
||||
|
||||
private final AvailablePortScanner portScanner;
|
||||
|
||||
private final MessageVerifier<?> contractVerifierMessaging;
|
||||
|
||||
private StubServer stubServer;
|
||||
|
||||
private final List<HttpServerStub> serverStubs;
|
||||
|
||||
StubRunnerExecutor(AvailablePortScanner portScanner, MessageVerifier<?> contractVerifierMessaging, List<HttpServerStub> serverStubs) {
|
||||
StubRunnerExecutor(AvailablePortScanner portScanner,
|
||||
MessageVerifier<?> contractVerifierMessaging,
|
||||
List<HttpServerStub> serverStubs) {
|
||||
this.portScanner = portScanner;
|
||||
this.contractVerifierMessaging = contractVerifierMessaging;
|
||||
this.serverStubs = serverStubs;
|
||||
}
|
||||
|
||||
StubRunnerExecutor(AvailablePortScanner portScanner, List<HttpServerStub> serverStubs) {
|
||||
StubRunnerExecutor(AvailablePortScanner portScanner,
|
||||
List<HttpServerStub> serverStubs) {
|
||||
this(portScanner, new NoOpStubMessages(), serverStubs);
|
||||
}
|
||||
|
||||
@@ -69,12 +75,12 @@ class StubRunnerExecutor implements StubFinder {
|
||||
this(portScanner, new NoOpStubMessages(), new ArrayList<HttpServerStub>());
|
||||
}
|
||||
|
||||
public RunningStubs runStubs(StubRunnerOptions stubRunnerOptions, StubRepository repository,
|
||||
StubConfiguration stubConfiguration) {
|
||||
public RunningStubs runStubs(StubRunnerOptions stubRunnerOptions,
|
||||
StubRepository repository, StubConfiguration stubConfiguration) {
|
||||
if (this.stubServer != null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Returning cached version of stubs [" + stubConfiguration.toColonSeparatedDependencyNotation()
|
||||
+ "]");
|
||||
log.debug("Returning cached version of stubs ["
|
||||
+ stubConfiguration.toColonSeparatedDependencyNotation() + "]");
|
||||
}
|
||||
return runningStubs();
|
||||
}
|
||||
@@ -85,8 +91,8 @@ class StubRunnerExecutor implements StubFinder {
|
||||
}
|
||||
|
||||
private RunningStubs runningStubs() {
|
||||
return new RunningStubs(
|
||||
Collections.singletonMap(this.stubServer.getStubConfiguration(), this.stubServer.getPort()));
|
||||
return new RunningStubs(Collections.singletonMap(
|
||||
this.stubServer.getStubConfiguration(), this.stubServer.getPort()));
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
@@ -103,11 +109,13 @@ class StubRunnerExecutor implements StubFinder {
|
||||
public URL findStubUrl(String groupId, String artifactId) {
|
||||
URL url = null;
|
||||
if (groupId == null) {
|
||||
url = findStubUrl(this.stubServer.stubConfiguration.artifactId.equals(artifactId));
|
||||
url = findStubUrl(
|
||||
this.stubServer.stubConfiguration.artifactId.equals(artifactId));
|
||||
}
|
||||
if (url == null) {
|
||||
url = findStubUrl(this.stubServer.stubConfiguration.artifactId.equals(artifactId)
|
||||
&& this.stubServer.stubConfiguration.groupId.equals(groupId));
|
||||
url = findStubUrl(
|
||||
this.stubServer.stubConfiguration.artifactId.equals(artifactId)
|
||||
&& this.stubServer.stubConfiguration.groupId.equals(groupId));
|
||||
}
|
||||
if (url == null) {
|
||||
throw new StubNotFoundException(groupId, artifactId);
|
||||
@@ -119,8 +127,8 @@ class StubRunnerExecutor implements StubFinder {
|
||||
public URL findStubUrl(String ivyNotation) {
|
||||
String[] splitString = ivyNotation.split(":", -1);
|
||||
if (splitString.length > 4) {
|
||||
throw new IllegalArgumentException(
|
||||
"[" + ivyNotation + "] is an invalid notation. Pass [groupId]:artifactId[:version][:classifier].");
|
||||
throw new IllegalArgumentException("[" + ivyNotation
|
||||
+ "] is an invalid notation. Pass [groupId]:artifactId[:version][:classifier].");
|
||||
}
|
||||
else if (splitString.length == 1) {
|
||||
return findStubUrl(null, splitString[0]);
|
||||
@@ -131,7 +139,8 @@ class StubRunnerExecutor implements StubFinder {
|
||||
else if (splitString.length == 3) {
|
||||
return findStubUrl(groupIdArtifactVersionMatches(splitString));
|
||||
}
|
||||
return findStubUrl(groupIdArtifactVersionMatches(splitString) && classifierMatches(splitString));
|
||||
return findStubUrl(groupIdArtifactVersionMatches(splitString)
|
||||
&& classifierMatches(splitString));
|
||||
}
|
||||
|
||||
private boolean classifierMatches(String[] splitString) {
|
||||
@@ -150,18 +159,21 @@ class StubRunnerExecutor implements StubFinder {
|
||||
|
||||
@Override
|
||||
public RunningStubs findAllRunningStubs() {
|
||||
return new RunningStubs(Collections.singletonMap(this.stubServer.stubConfiguration, this.stubServer.getPort()));
|
||||
return new RunningStubs(Collections.singletonMap(
|
||||
this.stubServer.stubConfiguration, this.stubServer.getPort()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<StubConfiguration, Collection<Contract>> getContracts() {
|
||||
return Collections.singletonMap(this.stubServer.stubConfiguration, this.stubServer.getContracts());
|
||||
return Collections.singletonMap(this.stubServer.stubConfiguration,
|
||||
this.stubServer.getContracts());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trigger(String ivyNotationAsString, String labelName) {
|
||||
Collection<Contract> matchingContracts = new ArrayList<>();
|
||||
for (Entry<StubConfiguration, Collection<Contract>> it : getContracts().entrySet()) {
|
||||
for (Entry<StubConfiguration, Collection<Contract>> it : getContracts()
|
||||
.entrySet()) {
|
||||
if (it.getKey().groupIdAndArtifactMatches(ivyNotationAsString)) {
|
||||
matchingContracts.addAll(it.getValue());
|
||||
}
|
||||
@@ -181,7 +193,8 @@ class StubRunnerExecutor implements StubFinder {
|
||||
private boolean triggerForDsls(Collection<Contract> dsls, String labelName) {
|
||||
Collection<Contract> matchingDsls = new ArrayList<>();
|
||||
for (Contract contract : dsls) {
|
||||
if (labelName.equals(contract.getLabel()) && contract.getOutputMessage() != null) {
|
||||
if (labelName.equals(contract.getLabel())
|
||||
&& contract.getOutputMessage() != null) {
|
||||
matchingDsls.add(contract);
|
||||
}
|
||||
}
|
||||
@@ -216,7 +229,8 @@ class StubRunnerExecutor implements StubFinder {
|
||||
@Override
|
||||
public Map<String, Collection<String>> labels() {
|
||||
Map<String, Collection<String>> labels = new LinkedHashMap<>();
|
||||
for (Entry<StubConfiguration, Collection<Contract>> it : getContracts().entrySet()) {
|
||||
for (Entry<StubConfiguration, Collection<Contract>> it : getContracts()
|
||||
.entrySet()) {
|
||||
Collection<String> values = new ArrayList<>();
|
||||
for (Contract contract : it.getValue()) {
|
||||
if (contract.getLabel() != null) {
|
||||
@@ -233,17 +247,18 @@ class StubRunnerExecutor implements StubFinder {
|
||||
DslProperty<?> body = outputMessage.getBody();
|
||||
Headers headers = outputMessage.getHeaders();
|
||||
this.contractVerifierMessaging.send(
|
||||
JsonOutput
|
||||
.toJson(BodyExtractor.extractClientValueFromBody(body == null ? null : body.getClientValue())),
|
||||
headers == null ? null : headers.asStubSideMap(), outputMessage.getSentTo().getClientValue());
|
||||
JsonOutput.toJson(BodyExtractor.extractClientValueFromBody(
|
||||
body == null ? null : body.getClientValue())),
|
||||
headers == null ? null : headers.asStubSideMap(),
|
||||
outputMessage.getSentTo().getClientValue());
|
||||
}
|
||||
|
||||
private URL returnStubUrlIfMatches(boolean condition) {
|
||||
return condition ? this.stubServer.getStubUrl() : null;
|
||||
}
|
||||
|
||||
private void startStubServers(final StubRunnerOptions stubRunnerOptions, final StubConfiguration stubConfiguration,
|
||||
StubRepository repository) {
|
||||
private void startStubServers(final StubRunnerOptions stubRunnerOptions,
|
||||
final StubConfiguration stubConfiguration, StubRepository repository) {
|
||||
final List<File> mappings = repository.getStubs();
|
||||
final Collection<Contract> contracts = repository.contracts;
|
||||
Integer port = stubRunnerOptions.port(stubConfiguration);
|
||||
@@ -251,20 +266,23 @@ class StubRunnerExecutor implements StubFinder {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("There are no HTTP related contracts. Won't start any servers");
|
||||
}
|
||||
this.stubServer = new StubServer(stubConfiguration, mappings, contracts, new NoOpHttpServerStub()).start();
|
||||
this.stubServer = new StubServer(stubConfiguration, mappings, contracts,
|
||||
new NoOpHttpServerStub()).start();
|
||||
return;
|
||||
}
|
||||
if (port != null && port >= 0) {
|
||||
this.stubServer = new StubServer(stubConfiguration, mappings, contracts, httpServerStub()).start(port);
|
||||
this.stubServer = new StubServer(stubConfiguration, mappings, contracts,
|
||||
httpServerStub()).start(port);
|
||||
}
|
||||
else {
|
||||
this.stubServer = this.portScanner.tryToExecuteWithFreePort(new PortCallback<StubServer>() {
|
||||
@Override
|
||||
public StubServer call(int availablePort) {
|
||||
return new StubServer(stubConfiguration, mappings, contracts,
|
||||
httpServerStub()).start(availablePort);
|
||||
}
|
||||
});
|
||||
this.stubServer = this.portScanner
|
||||
.tryToExecuteWithFreePort(new PortCallback<StubServer>() {
|
||||
@Override
|
||||
public StubServer call(int availablePort) {
|
||||
return new StubServer(stubConfiguration, mappings, contracts,
|
||||
httpServerStub()).start(availablePort);
|
||||
}
|
||||
});
|
||||
}
|
||||
STUB_SERVERS.add(this.stubServer);
|
||||
}
|
||||
|
||||
@@ -32,15 +32,17 @@ import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
|
||||
*/
|
||||
class StubRunnerFactory {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
private static final Log log = LogFactory
|
||||
.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final StubRunnerOptions stubRunnerOptions;
|
||||
|
||||
private final StubDownloader stubDownloader;
|
||||
|
||||
private final MessageVerifier<?> contractVerifierMessaging;
|
||||
|
||||
public StubRunnerFactory(StubRunnerOptions stubRunnerOptions,
|
||||
StubDownloader stubDownloader,
|
||||
MessageVerifier<?> contractVerifierMessaging) {
|
||||
StubDownloader stubDownloader, MessageVerifier<?> contractVerifierMessaging) {
|
||||
this.stubRunnerOptions = stubRunnerOptions;
|
||||
this.stubDownloader = stubDownloader;
|
||||
this.contractVerifierMessaging = contractVerifierMessaging;
|
||||
@@ -48,18 +50,22 @@ class StubRunnerFactory {
|
||||
|
||||
public Collection<StubRunner> createStubsFromServiceConfiguration() {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will download stubs for dependencies " + this.stubRunnerOptions.getDependencies());
|
||||
log.debug("Will download stubs for dependencies "
|
||||
+ this.stubRunnerOptions.getDependencies());
|
||||
}
|
||||
if (this.stubRunnerOptions.getDependencies().isEmpty()) {
|
||||
log.warn("No stubs to download have been passed. Most likely you have forgotten to pass "
|
||||
+ "them either via annotation or a property");
|
||||
log.warn(
|
||||
"No stubs to download have been passed. Most likely you have forgotten to pass "
|
||||
+ "them either via annotation or a property");
|
||||
}
|
||||
Collection<StubRunner> result = new ArrayList<>();
|
||||
for (StubConfiguration stubsConfiguration : this.stubRunnerOptions.getDependencies()) {
|
||||
for (StubConfiguration stubsConfiguration : this.stubRunnerOptions
|
||||
.getDependencies()) {
|
||||
Map.Entry<StubConfiguration, File> entry = this.stubDownloader
|
||||
.downloadAndUnpackStubJar(stubsConfiguration);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("For stub configuration [" + stubsConfiguration + "] the downloaded entry is [" + entry + "]");
|
||||
log.debug("For stub configuration [" + stubsConfiguration
|
||||
+ "] the downloaded entry is [" + entry + "]");
|
||||
}
|
||||
if (entry != null) {
|
||||
result.add(createStubRunner(entry.getKey(), entry.getValue()));
|
||||
@@ -74,7 +80,8 @@ class StubRunnerFactory {
|
||||
if (unzipedStubDir == null) {
|
||||
return null;
|
||||
}
|
||||
return createStubRunner(unzipedStubDir, stubsConfiguration, this.stubRunnerOptions);
|
||||
return createStubRunner(unzipedStubDir, stubsConfiguration,
|
||||
this.stubRunnerOptions);
|
||||
}
|
||||
|
||||
private StubRunner createStubRunner(File unzippedStubsDir,
|
||||
|
||||
@@ -41,49 +41,55 @@ public class StubRunnerMain {
|
||||
private StubRunnerMain(String[] args) throws Exception {
|
||||
OptionParser parser = new OptionParser();
|
||||
try {
|
||||
ArgumentAcceptingOptionSpec<Integer> minPortValueOpt = parser
|
||||
.acceptsAll(Arrays.asList("minp", "minPort"),
|
||||
"Minimum port value to be assigned to the WireMock instance. Defaults to 10000")
|
||||
ArgumentAcceptingOptionSpec<Integer> minPortValueOpt = parser.acceptsAll(
|
||||
Arrays.asList("minp", "minPort"),
|
||||
"Minimum port value to be assigned to the WireMock instance. Defaults to 10000")
|
||||
.withRequiredArg().ofType(Integer.class).defaultsTo(10000);
|
||||
ArgumentAcceptingOptionSpec<Integer> maxPortValueOpt = parser
|
||||
.acceptsAll(Arrays.asList("maxp", "maxPort"),
|
||||
"Maximum port value to be assigned to the WireMock instance. Defaults to 15000")
|
||||
ArgumentAcceptingOptionSpec<Integer> maxPortValueOpt = parser.acceptsAll(
|
||||
Arrays.asList("maxp", "maxPort"),
|
||||
"Maximum port value to be assigned to the WireMock instance. Defaults to 15000")
|
||||
.withRequiredArg().ofType(Integer.class).defaultsTo(15000);
|
||||
ArgumentAcceptingOptionSpec<String> stubsOpt = parser
|
||||
.acceptsAll(Arrays.asList("s", "stubs"),
|
||||
"Comma separated list of Ivy representation of jars with stubs. Eg. groupid:artifactid1,groupid2:artifactid2:classifier")
|
||||
ArgumentAcceptingOptionSpec<String> stubsOpt = parser.acceptsAll(
|
||||
Arrays.asList("s", "stubs"),
|
||||
"Comma separated list of Ivy representation of jars with stubs. Eg. groupid:artifactid1,groupid2:artifactid2:classifier")
|
||||
.withRequiredArg();
|
||||
ArgumentAcceptingOptionSpec<String> classifierOpt = parser
|
||||
.acceptsAll(Arrays.asList("c", "classifier"),
|
||||
"Suffix for the jar containing stubs (e.g. 'stubs' if the stub jar would have a 'stubs' classifier for stubs: foobar-stubs ). Defaults to 'stubs'")
|
||||
ArgumentAcceptingOptionSpec<String> classifierOpt = parser.acceptsAll(
|
||||
Arrays.asList("c", "classifier"),
|
||||
"Suffix for the jar containing stubs (e.g. 'stubs' if the stub jar would have a 'stubs' classifier for stubs: foobar-stubs ). Defaults to 'stubs'")
|
||||
.withRequiredArg().defaultsTo("stubs");
|
||||
ArgumentAcceptingOptionSpec<String> rootOpt = parser
|
||||
.acceptsAll(Arrays.asList("r", "root"),"Location of a Jar containing server where you keep your stubs (e.g. http://nexus.net/content/repositories/repository)")
|
||||
ArgumentAcceptingOptionSpec<String> rootOpt = parser.acceptsAll(
|
||||
Arrays.asList("r", "root"),
|
||||
"Location of a Jar containing server where you keep your stubs (e.g. http://nexus.net/content/repositories/repository)")
|
||||
.withRequiredArg();
|
||||
ArgumentAcceptingOptionSpec<String> usernameOpt = parser
|
||||
.acceptsAll(Arrays.asList("u", "username"),"Username to user when connecting to repository")
|
||||
.acceptsAll(Arrays.asList("u", "username"),
|
||||
"Username to user when connecting to repository")
|
||||
.withOptionalArg();
|
||||
ArgumentAcceptingOptionSpec<String> passwordOpt = parser
|
||||
.acceptsAll(Arrays.asList("p", "password"),"Password to user when connecting to repository")
|
||||
.acceptsAll(Arrays.asList("p", "password"),
|
||||
"Password to user when connecting to repository")
|
||||
.withOptionalArg();
|
||||
ArgumentAcceptingOptionSpec<String> proxyHostOpt = parser
|
||||
.acceptsAll(Arrays.asList("phost", "proxyHost"),"Proxy host to use for repository requests")
|
||||
.acceptsAll(Arrays.asList("phost", "proxyHost"),
|
||||
"Proxy host to use for repository requests")
|
||||
.withOptionalArg();
|
||||
ArgumentAcceptingOptionSpec<Integer> proxyPortOpt = parser
|
||||
.acceptsAll(Arrays.asList("pport", "proxyPort"),"Proxy port to use for repository requests")
|
||||
.withOptionalArg()
|
||||
.ofType(Integer.class);
|
||||
.acceptsAll(Arrays.asList("pport", "proxyPort"),
|
||||
"Proxy port to use for repository requests")
|
||||
.withOptionalArg().ofType(Integer.class);
|
||||
ArgumentAcceptingOptionSpec<String> stubsMode = parser
|
||||
.acceptsAll(Arrays.asList("sm", "stubsMode"),"Stubs mode to be used. Acceptable values " + Arrays
|
||||
.toString(StubRunnerProperties.StubsMode.values()))
|
||||
.withRequiredArg().defaultsTo(StubRunnerProperties.StubsMode.CLASSPATH.toString());
|
||||
.acceptsAll(Arrays.asList("sm", "stubsMode"),
|
||||
"Stubs mode to be used. Acceptable values " + Arrays
|
||||
.toString(StubRunnerProperties.StubsMode.values()))
|
||||
.withRequiredArg()
|
||||
.defaultsTo(StubRunnerProperties.StubsMode.CLASSPATH.toString());
|
||||
OptionSet options = parser.parse(args);
|
||||
String stubs = options.valueOf(stubsOpt);
|
||||
StubRunnerProperties.StubsMode stubsModeValue = StubRunnerProperties.StubsMode.valueOf(
|
||||
options.valueOf(stubsMode));
|
||||
StubRunnerProperties.StubsMode stubsModeValue = StubRunnerProperties.StubsMode
|
||||
.valueOf(options.valueOf(stubsMode));
|
||||
Integer minPortValue = options.valueOf(minPortValueOpt);
|
||||
Integer maxPortValue = options.valueOf(maxPortValueOpt);
|
||||
String stubRepositoryRoot= options.valueOf(rootOpt);
|
||||
String stubRepositoryRoot = options.valueOf(rootOpt);
|
||||
String stubsSuffix = options.valueOf(classifierOpt);
|
||||
final String username = options.valueOf(usernameOpt);
|
||||
final String password = options.valueOf(passwordOpt);
|
||||
@@ -93,9 +99,7 @@ public class StubRunnerMain {
|
||||
.withMinMaxPort(minPortValue, maxPortValue)
|
||||
.withStubRepositoryRoot(stubRepositoryRoot)
|
||||
.withStubsMode(stubsModeValue).withStubsClassifier(stubsSuffix)
|
||||
.withUsername(username)
|
||||
.withPassword(password)
|
||||
.withStubs(stubs);
|
||||
.withUsername(username).withPassword(password).withStubs(stubs);
|
||||
if (proxyHost != null) {
|
||||
builder.withProxy(proxyHost, proxyPort);
|
||||
}
|
||||
|
||||
@@ -94,35 +94,38 @@ public class StubRunnerOptions {
|
||||
private String consumerName;
|
||||
|
||||
/**
|
||||
* For debugging purposes you can output the registered mappings to a given folder. Each HTTP server
|
||||
* stub will have its own subfolder where all the mappings will get stored.
|
||||
* For debugging purposes you can output the registered mappings to a given folder.
|
||||
* Each HTTP server stub will have its own subfolder where all the mappings will get
|
||||
* stored.
|
||||
*/
|
||||
private String mappingsOutputFolder;
|
||||
|
||||
final StubRunnerProperties.StubsMode stubsMode;
|
||||
|
||||
/**
|
||||
* If set to {@code false} will NOT delete stubs from a temporary
|
||||
* folder after running tests
|
||||
* If set to {@code false} will NOT delete stubs from a temporary folder after running
|
||||
* tests
|
||||
*/
|
||||
private boolean deleteStubsAfterTest;
|
||||
|
||||
/**
|
||||
* Map of properties that can be passed to custom {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
|
||||
* Map of properties that can be passed to custom
|
||||
* {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
|
||||
*/
|
||||
private Map<String, String> properties = new HashMap<>();
|
||||
|
||||
StubRunnerOptions(Integer minPortValue, Integer maxPortValue,
|
||||
Resource stubRepositoryRoot, StubRunnerProperties.StubsMode stubsMode, String stubsClassifier,
|
||||
Collection<StubConfiguration> dependencies,
|
||||
Map<StubConfiguration, Integer> stubIdsToPortMapping,
|
||||
String username, String password, final StubRunnerProxyOptions stubRunnerProxyOptions,
|
||||
Resource stubRepositoryRoot, StubRunnerProperties.StubsMode stubsMode,
|
||||
String stubsClassifier, Collection<StubConfiguration> dependencies,
|
||||
Map<StubConfiguration, Integer> stubIdsToPortMapping, String username,
|
||||
String password, final StubRunnerProxyOptions stubRunnerProxyOptions,
|
||||
boolean stubsPerConsumer, String consumerName, String mappingsOutputFolder,
|
||||
boolean deleteStubsAfterTest, Map<String, String> properties) {
|
||||
this.minPortValue = minPortValue;
|
||||
this.maxPortValue = maxPortValue;
|
||||
this.stubRepositoryRoot = stubRepositoryRoot;
|
||||
this.stubsMode = stubsMode != null ? stubsMode : StubRunnerProperties.StubsMode.CLASSPATH;
|
||||
this.stubsMode = stubsMode != null ? stubsMode
|
||||
: StubRunnerProperties.StubsMode.CLASSPATH;
|
||||
this.stubsClassifier = stubsClassifier;
|
||||
this.dependencies = dependencies;
|
||||
this.stubIdsToPortMapping = stubIdsToPortMapping;
|
||||
@@ -147,8 +150,10 @@ public class StubRunnerOptions {
|
||||
|
||||
public static StubRunnerOptions fromSystemProps() {
|
||||
StubRunnerOptionsBuilder builder = new StubRunnerOptionsBuilder()
|
||||
.withMinPort(Integer.valueOf(System.getProperty("stubrunner.port.range.min", "10000")))
|
||||
.withMaxPort(Integer.valueOf(System.getProperty("stubrunner.port.range.max", "15000")))
|
||||
.withMinPort(Integer.valueOf(
|
||||
System.getProperty("stubrunner.port.range.min", "10000")))
|
||||
.withMaxPort(Integer.valueOf(
|
||||
System.getProperty("stubrunner.port.range.max", "15000")))
|
||||
.withStubRepositoryRoot(ResourceResolver
|
||||
.resource(System.getProperty("stubrunner.repository.root", "")))
|
||||
.withStubsMode(System.getProperty("stubrunner.stubs-mode", "LOCAL"))
|
||||
@@ -156,14 +161,18 @@ public class StubRunnerOptions {
|
||||
.withStubs(System.getProperty("stubrunner.ids", ""))
|
||||
.withUsername(System.getProperty("stubrunner.username"))
|
||||
.withPassword(System.getProperty("stubrunner.password"))
|
||||
.withStubPerConsumer(Boolean.parseBoolean(System.getProperty("stubrunner.stubs-per-consumer", "false")))
|
||||
.withStubPerConsumer(Boolean.parseBoolean(
|
||||
System.getProperty("stubrunner.stubs-per-consumer", "false")))
|
||||
.withConsumerName(System.getProperty("stubrunner.consumer-name"))
|
||||
.withMappingsOutputFolder(System.getProperty("stubrunner.mappings-output-folder"))
|
||||
.withDeleteStubsAfterTest(Boolean.parseBoolean(System.getProperty("stubrunner.delete-stubs-after-test", "true")))
|
||||
.withMappingsOutputFolder(
|
||||
System.getProperty("stubrunner.mappings-output-folder"))
|
||||
.withDeleteStubsAfterTest(Boolean.parseBoolean(
|
||||
System.getProperty("stubrunner.delete-stubs-after-test", "true")))
|
||||
.withProperties(stubRunnerProps());
|
||||
String proxyHost = System.getProperty("stubrunner.proxy.host");
|
||||
if (proxyHost != null) {
|
||||
builder.withProxy(proxyHost, Integer.parseInt(System.getProperty("stubrunner.proxy.port")));
|
||||
builder.withProxy(proxyHost,
|
||||
Integer.parseInt(System.getProperty("stubrunner.proxy.port")));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
@@ -172,12 +181,12 @@ public class StubRunnerOptions {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
Properties properties = System.getProperties();
|
||||
Set<String> propertyNames = properties.stringPropertyNames();
|
||||
propertyNames
|
||||
.stream()
|
||||
propertyNames.stream()
|
||||
// stubrunner.properties.foo.bar=baz
|
||||
.filter(s -> s.toLowerCase().startsWith("stubrunner.properties"))
|
||||
// foo.bar=baz
|
||||
.forEach(s -> map.put(s.substring("stubrunner.properties".length() + 1), System.getProperty(s)));
|
||||
.forEach(s -> map.put(s.substring("stubrunner.properties".length() + 1),
|
||||
System.getProperty(s)));
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -287,6 +296,7 @@ public class StubRunnerOptions {
|
||||
public static class StubRunnerProxyOptions {
|
||||
|
||||
private final String proxyHost;
|
||||
|
||||
private final int proxyPort;
|
||||
|
||||
public StubRunnerProxyOptions(final String proxyHost, final int proxyPort) {
|
||||
@@ -302,25 +312,30 @@ public class StubRunnerOptions {
|
||||
return this.proxyPort;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StubRunnerProxyOptions{" + "proxyHost='" + this.proxyHost + '\''
|
||||
+ ", proxyPort=" + this.proxyPort + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "StubRunnerOptions{" + "minPortValue=" + this.minPortValue + ", maxPortValue="
|
||||
+ this.maxPortValue + ", stubRepositoryRoot='" + this.stubRepositoryRoot + '\''
|
||||
+ ", stubsMode='" + this.stubsMode + "', stubsClassifier='" + this.stubsClassifier
|
||||
+ '\'' + ", dependencies=" + this.dependencies + ", stubIdsToPortMapping="
|
||||
+ this.stubIdsToPortMapping + ", username='" + obfuscate(this.username) + '\'' + ", password='"
|
||||
+ obfuscate(this.password) + '\'' + ", stubRunnerProxyOptions='" + this.stubRunnerProxyOptions + "', stubsPerConsumer='"
|
||||
+ this.stubsPerConsumer
|
||||
+ '\'' + ", stubsPerConsumer='" + this.stubsPerConsumer + '\''
|
||||
+ '}';
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StubRunnerOptions{" + "minPortValue=" + this.minPortValue
|
||||
+ ", maxPortValue=" + this.maxPortValue + ", stubRepositoryRoot='"
|
||||
+ this.stubRepositoryRoot + '\'' + ", stubsMode='" + this.stubsMode
|
||||
+ "', stubsClassifier='" + this.stubsClassifier + '\'' + ", dependencies="
|
||||
+ this.dependencies + ", stubIdsToPortMapping="
|
||||
+ this.stubIdsToPortMapping + ", username='" + obfuscate(this.username)
|
||||
+ '\'' + ", password='" + obfuscate(this.password) + '\''
|
||||
+ ", stubRunnerProxyOptions='" + this.stubRunnerProxyOptions
|
||||
+ "', stubsPerConsumer='" + this.stubsPerConsumer + '\''
|
||||
+ ", stubsPerConsumer='" + this.stubsPerConsumer + '\'' + '}';
|
||||
}
|
||||
|
||||
private String obfuscate(String string) {
|
||||
return StringUtils.hasText(string) ? "****" : "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,22 +33,37 @@ import org.springframework.util.StringUtils;
|
||||
public class StubRunnerOptionsBuilder {
|
||||
|
||||
private static final String DELIMITER = ":";
|
||||
|
||||
private LinkedList<String> stubs = new LinkedList<>();
|
||||
|
||||
private Collection<StubConfiguration> stubConfigurations = new ArrayList<>();
|
||||
|
||||
private Map<StubConfiguration, Integer> stubIdsToPortMapping = new LinkedHashMap<>();
|
||||
|
||||
private Integer minPortValue = 10000;
|
||||
|
||||
private Integer maxPortValue = 15000;
|
||||
|
||||
private Resource stubRepositoryRoot;
|
||||
|
||||
private String stubsClassifier = "stubs";
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private StubRunnerOptions.StubRunnerProxyOptions stubRunnerProxyOptions;
|
||||
|
||||
private boolean stubsPerConsumer = false;
|
||||
|
||||
private String consumerName;
|
||||
|
||||
private String mappingsOutputFolder;
|
||||
|
||||
private StubRunnerProperties.StubsMode stubsMode;
|
||||
|
||||
private boolean deleteStubsAfterTest = true;
|
||||
|
||||
private Map<String, String> properties = new HashMap<>();
|
||||
|
||||
public StubRunnerOptionsBuilder() {
|
||||
@@ -70,7 +85,8 @@ public class StubRunnerOptionsBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public StubRunnerOptionsBuilder withMinMaxPort(Integer minPortValue, Integer maxPortValue) {
|
||||
public StubRunnerOptionsBuilder withMinMaxPort(Integer minPortValue,
|
||||
Integer maxPortValue) {
|
||||
this.minPortValue = minPortValue;
|
||||
this.maxPortValue = maxPortValue;
|
||||
return this;
|
||||
@@ -98,7 +114,8 @@ public class StubRunnerOptionsBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public StubRunnerOptionsBuilder withStubsMode(StubRunnerProperties.StubsMode stubsMode) {
|
||||
public StubRunnerOptionsBuilder withStubsMode(
|
||||
StubRunnerProperties.StubsMode stubsMode) {
|
||||
this.stubsMode = stubsMode;
|
||||
return this;
|
||||
}
|
||||
@@ -131,21 +148,23 @@ public class StubRunnerOptionsBuilder {
|
||||
this.stubsPerConsumer = options.isStubsPerConsumer();
|
||||
this.consumerName = options.getConsumerName();
|
||||
this.mappingsOutputFolder = options.getMappingsOutputFolder();
|
||||
this.stubConfigurations = options.dependencies != null ?
|
||||
options.dependencies : new ArrayList<>();
|
||||
this.stubIdsToPortMapping = options.stubIdsToPortMapping != null ?
|
||||
options.stubIdsToPortMapping : new LinkedHashMap<>();
|
||||
this.stubConfigurations = options.dependencies != null ? options.dependencies
|
||||
: new ArrayList<>();
|
||||
this.stubIdsToPortMapping = options.stubIdsToPortMapping != null
|
||||
? options.stubIdsToPortMapping : new LinkedHashMap<>();
|
||||
this.deleteStubsAfterTest = options.isDeleteStubsAfterTest();
|
||||
this.properties = options.getProperties();
|
||||
return this;
|
||||
}
|
||||
|
||||
public StubRunnerOptionsBuilder withMappingsOutputFolder(String mappingsOutputFolder) {
|
||||
public StubRunnerOptionsBuilder withMappingsOutputFolder(
|
||||
String mappingsOutputFolder) {
|
||||
this.mappingsOutputFolder = mappingsOutputFolder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StubRunnerOptionsBuilder withDeleteStubsAfterTest(boolean deleteStubsAfterTest) {
|
||||
public StubRunnerOptionsBuilder withDeleteStubsAfterTest(
|
||||
boolean deleteStubsAfterTest) {
|
||||
this.deleteStubsAfterTest = deleteStubsAfterTest;
|
||||
return this;
|
||||
}
|
||||
@@ -156,15 +175,17 @@ public class StubRunnerOptionsBuilder {
|
||||
}
|
||||
|
||||
public StubRunnerOptions build() {
|
||||
return new StubRunnerOptions(this.minPortValue, this.maxPortValue, this.stubRepositoryRoot,
|
||||
this.stubsMode, this.stubsClassifier, buildDependencies(), this.stubIdsToPortMapping,
|
||||
this.username, this.password, this.stubRunnerProxyOptions, this.stubsPerConsumer, this.consumerName,
|
||||
this.mappingsOutputFolder, this.deleteStubsAfterTest, this.properties);
|
||||
return new StubRunnerOptions(this.minPortValue, this.maxPortValue,
|
||||
this.stubRepositoryRoot, this.stubsMode, this.stubsClassifier,
|
||||
buildDependencies(), this.stubIdsToPortMapping, this.username,
|
||||
this.password, this.stubRunnerProxyOptions, this.stubsPerConsumer,
|
||||
this.consumerName, this.mappingsOutputFolder, this.deleteStubsAfterTest,
|
||||
this.properties);
|
||||
}
|
||||
|
||||
private Collection<StubConfiguration> buildDependencies() {
|
||||
List<StubConfiguration> stubConfigurations = StubsParser
|
||||
.fromString(this.stubs, this.stubsClassifier);
|
||||
List<StubConfiguration> stubConfigurations = StubsParser.fromString(this.stubs,
|
||||
this.stubsClassifier);
|
||||
this.stubConfigurations.addAll(stubConfigurations);
|
||||
return this.stubConfigurations;
|
||||
}
|
||||
@@ -174,14 +195,17 @@ public class StubRunnerOptionsBuilder {
|
||||
if (stubIdsToPortMapping.length == 1 && !containsRange(stubIdsToPortMapping[0])) {
|
||||
list.addAll(StringUtils.commaDelimitedListToSet(stubIdsToPortMapping[0]));
|
||||
return list;
|
||||
} else if (stubIdsToPortMapping.length == 1 && containsRange(stubIdsToPortMapping[0])) {
|
||||
}
|
||||
else if (stubIdsToPortMapping.length == 1
|
||||
&& containsRange(stubIdsToPortMapping[0])) {
|
||||
LinkedList<String> linkedList = new LinkedList<>();
|
||||
String[] split = stubIdsToPortMapping[0].split(",");
|
||||
for (String string : split) {
|
||||
if (containsClosingRange(string)) {
|
||||
String last = linkedList.pop();
|
||||
linkedList.push(last + "," + string);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
linkedList.push(string);
|
||||
}
|
||||
}
|
||||
@@ -210,7 +234,8 @@ public class StubRunnerOptionsBuilder {
|
||||
if (StubsParser.hasPort(notation)) {
|
||||
addPort(notation);
|
||||
this.stubs.add(StubsParser.ivyFromStringWithPort(notation));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
this.stubs.add(notation);
|
||||
}
|
||||
}
|
||||
@@ -234,8 +259,10 @@ public class StubRunnerOptionsBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public StubRunnerOptionsBuilder withProxy(final String proxyHost, final int proxyPort) {
|
||||
this.stubRunnerProxyOptions = new StubRunnerOptions.StubRunnerProxyOptions(proxyHost, proxyPort);
|
||||
public StubRunnerOptionsBuilder withProxy(final String proxyHost,
|
||||
final int proxyPort) {
|
||||
this.stubRunnerProxyOptions = new StubRunnerOptions.StubRunnerProxyOptions(
|
||||
proxyHost, proxyPort);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -248,4 +275,5 @@ public class StubRunnerOptionsBuilder {
|
||||
this.consumerName = consumerName;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ class StubRunnerPropertyUtils {
|
||||
static PropertyFetcher FETCHER = new PropertyFetcher();
|
||||
|
||||
/**
|
||||
* For Env vars takes the prop name, converts dots to underscores and applies
|
||||
* upper case
|
||||
* For Env vars takes the prop name, converts dots to underscores and applies upper
|
||||
* case
|
||||
*/
|
||||
static boolean isPropertySet(String propName) {
|
||||
String value = getProperty(new HashMap<>(), propName);
|
||||
@@ -47,8 +47,7 @@ class StubRunnerPropertyUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* For options, system props and env vars returns {@code true}
|
||||
* when property is set
|
||||
* For options, system props and env vars returns {@code true} when property is set
|
||||
*/
|
||||
static boolean hasProperty(Map<String, String> options, String propName) {
|
||||
String value = getProperty(options, propName);
|
||||
@@ -56,14 +55,15 @@ class StubRunnerPropertyUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to pick a value from options, for Env vars takes the prop name, converts
|
||||
* dots to underscores and applies upper case
|
||||
* Tries to pick a value from options, for Env vars takes the prop name, converts dots
|
||||
* to underscores and applies upper case
|
||||
*/
|
||||
static String getProperty(Map<String, String> options, String propName) {
|
||||
if (options != null && options.containsKey(propName)) {
|
||||
String value = options.get(propName);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Options map contains the prop [" + propName + "] with value [" + value + "]");
|
||||
log.trace("Options map contains the prop [" + propName + "] with value ["
|
||||
+ value + "]");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -81,7 +81,8 @@ class StubRunnerPropertyUtils {
|
||||
String systemProp = FETCHER.systemProp(stubRunnerProp);
|
||||
if (StringUtils.hasText(systemProp)) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("System property [" + stubRunnerProp + "] has value [" + systemProp + "]");
|
||||
log.trace("System property [" + stubRunnerProp + "] has value ["
|
||||
+ systemProp + "]");
|
||||
}
|
||||
return systemProp;
|
||||
}
|
||||
@@ -89,17 +90,22 @@ class StubRunnerPropertyUtils {
|
||||
.replaceAll("-", "_").toUpperCase();
|
||||
String envVar = FETCHER.envVar(convertedEnvProp);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Environment variable [" + convertedEnvProp + "] has value [" + envVar + "]");
|
||||
log.trace("Environment variable [" + convertedEnvProp + "] has value ["
|
||||
+ envVar + "]");
|
||||
}
|
||||
return envVar;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PropertyFetcher {
|
||||
|
||||
String systemProp(String prop) {
|
||||
return System.getProperty(prop);
|
||||
}
|
||||
|
||||
String envVar(String prop) {
|
||||
return System.getenv(prop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import java.io.Closeable;
|
||||
public interface StubRunning extends Closeable, StubFinder {
|
||||
|
||||
/**
|
||||
* Runs the stubs and returns the {@link RunningStubs}. If the stubs were
|
||||
* already started then a cached version will be returned.
|
||||
* Runs the stubs and returns the {@link RunningStubs}. If the stubs were already
|
||||
* started then a cached version will be returned.
|
||||
*/
|
||||
RunningStubs runStubs();
|
||||
|
||||
|
||||
@@ -31,8 +31,11 @@ class StubServer {
|
||||
private static final Log log = LogFactory.getLog(StubServer.class);
|
||||
|
||||
private final HttpServerStub httpServerStub;
|
||||
|
||||
final StubConfiguration stubConfiguration;
|
||||
|
||||
final Collection<File> mappings;
|
||||
|
||||
final Collection<Contract> contracts;
|
||||
|
||||
StubServer(StubConfiguration stubConfiguration, Collection<File> mappings,
|
||||
@@ -54,7 +57,8 @@ class StubServer {
|
||||
}
|
||||
|
||||
private StubServer stubServer() {
|
||||
log.info("Started stub server for project [" + this.stubConfiguration.toColonSeparatedDependencyNotation()
|
||||
log.info("Started stub server for project ["
|
||||
+ this.stubConfiguration.toColonSeparatedDependencyNotation()
|
||||
+ "] on port " + this.httpServerStub.port());
|
||||
this.httpServerStub.registerMappings(this.mappings);
|
||||
return this;
|
||||
@@ -103,22 +107,26 @@ class StubServer {
|
||||
return this.httpServerStub.registeredMappings();
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
StubServer that = (StubServer) o;
|
||||
return Objects.equals(this.stubConfiguration, that.stubConfiguration) && Objects
|
||||
.equals(this.contracts, that.contracts);
|
||||
return Objects.equals(this.stubConfiguration, that.stubConfiguration)
|
||||
&& Objects.equals(this.contracts, that.contracts);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.stubConfiguration, this.contracts);
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "StubServer{" + "stubConfiguration=" + this.stubConfiguration + ", mappingsSize="
|
||||
+ this.mappings.size() + '}';
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StubServer{" + "stubConfiguration=" + this.stubConfiguration
|
||||
+ ", mappingsSize=" + this.mappings.size() + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@ import java.util.Map;
|
||||
public interface StubTrigger {
|
||||
|
||||
/**
|
||||
* Triggers an event by a given label for a given {@code groupid:artifactid} notation. You can use only {@code artifactId} too.
|
||||
* Triggers an event by a given label for a given {@code groupid:artifactid} notation.
|
||||
* You can use only {@code artifactId} too.
|
||||
*
|
||||
* Feature related to messaging.
|
||||
*
|
||||
* @return true - if managed to run a trigger
|
||||
*/
|
||||
boolean trigger(String ivyNotation, String labelName);
|
||||
@@ -34,7 +34,6 @@ public interface StubTrigger {
|
||||
* Triggers an event by a given label.
|
||||
*
|
||||
* Feature related to messaging.
|
||||
*
|
||||
* @return true - if managed to run a trigger
|
||||
*/
|
||||
boolean trigger(String labelName);
|
||||
@@ -43,7 +42,6 @@ public interface StubTrigger {
|
||||
* Triggers all possible events.
|
||||
*
|
||||
* Feature related to messaging.
|
||||
*
|
||||
* @return true - if managed to run a trigger
|
||||
*/
|
||||
boolean trigger();
|
||||
@@ -54,4 +52,5 @@ public interface StubTrigger {
|
||||
* Feature related to messaging.
|
||||
*/
|
||||
Map<String, Collection<String>> labels();
|
||||
|
||||
}
|
||||
@@ -42,9 +42,9 @@ class TemporaryFileStorage {
|
||||
private static final Log log = LogFactory.getLog(TemporaryFileStorage.class);
|
||||
|
||||
/**
|
||||
* There are problems with removal of stubs unpacked to a temporary folder.
|
||||
* That's why we're creating a bounded in-memory storage of unpacked files
|
||||
* and later we register a shutdown hook to remove all these files.
|
||||
* There are problems with removal of stubs unpacked to a temporary folder. That's why
|
||||
* we're creating a bounded in-memory storage of unpacked files and later we register
|
||||
* a shutdown hook to remove all these files.
|
||||
*/
|
||||
private static final Queue<File> TEMP_FILES_LOG = new LinkedBlockingQueue<>(1000);
|
||||
|
||||
@@ -66,8 +66,8 @@ class TemporaryFileStorage {
|
||||
if (file.isDirectory()) {
|
||||
Files.walkFileTree(file.toPath(), new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws
|
||||
IOException {
|
||||
public FileVisitResult visitFile(Path file,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Removing file [" + file + "]");
|
||||
}
|
||||
@@ -76,7 +76,8 @@ class TemporaryFileStorage {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
public FileVisitResult postVisitDirectory(Path dir,
|
||||
IOException exc) throws IOException {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Removing dir [" + dir + "]");
|
||||
}
|
||||
@@ -84,11 +85,13 @@ class TemporaryFileStorage {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Files.delete(file.toPath());
|
||||
}
|
||||
}
|
||||
} catch (NoClassDefFoundError | IOException e) {
|
||||
}
|
||||
catch (NoClassDefFoundError | IOException e) {
|
||||
// Added NoClassDefFoundError cause sometimes it's visible in the builds
|
||||
// this error is completely harmless
|
||||
if (log.isTraceEnabled()) {
|
||||
@@ -99,12 +102,12 @@ class TemporaryFileStorage {
|
||||
|
||||
static File createTempDir(String tempDirPrefix) {
|
||||
try {
|
||||
return createTempDirectory(tempDirPrefix)
|
||||
.toFile();
|
||||
return createTempDirectory(tempDirPrefix).toFile();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot create tmp dir with prefix: [" + tempDirPrefix + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,12 +43,18 @@ import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptions {
|
||||
|
||||
private static final String DELIMITER = ":";
|
||||
|
||||
private static final String LATEST_VERSION = "+";
|
||||
|
||||
StubRunnerOptionsBuilder stubRunnerOptionsBuilder = new StubRunnerOptionsBuilder(StubRunnerOptions.fromSystemProps());
|
||||
StubRunnerOptionsBuilder stubRunnerOptionsBuilder = new StubRunnerOptionsBuilder(
|
||||
StubRunnerOptions.fromSystemProps());
|
||||
|
||||
BatchStubRunner stubFinder;
|
||||
|
||||
MessageVerifier verifier = new ExceptionThrowingMessageVerifier();
|
||||
|
||||
StubRunnerRule delegate = this;
|
||||
|
||||
public StubRunnerRule() {
|
||||
@@ -65,102 +71,122 @@ public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptio
|
||||
}
|
||||
|
||||
private void before() {
|
||||
stubFinder(new BatchStubRunnerFactory(builder().build(), verifier()).buildBatchStubRunner());
|
||||
stubFinder(new BatchStubRunnerFactory(builder().build(), verifier())
|
||||
.buildBatchStubRunner());
|
||||
StubRunnerRule.this.stubFinder().runStubs();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule messageVerifier(MessageVerifier messageVerifier) {
|
||||
@Override
|
||||
public StubRunnerRule messageVerifier(MessageVerifier messageVerifier) {
|
||||
verifier(messageVerifier);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule options(StubRunnerOptions stubRunnerOptions) {
|
||||
@Override
|
||||
public StubRunnerRule options(StubRunnerOptions stubRunnerOptions) {
|
||||
builder().withOptions(stubRunnerOptions);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule minPort(int minPort) {
|
||||
@Override
|
||||
public StubRunnerRule minPort(int minPort) {
|
||||
builder().withMinPort(minPort);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule maxPort(int maxPort) {
|
||||
@Override
|
||||
public StubRunnerRule maxPort(int maxPort) {
|
||||
builder().withMaxPort(maxPort);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule repoRoot(String repoRoot) {
|
||||
@Override
|
||||
public StubRunnerRule repoRoot(String repoRoot) {
|
||||
builder().withStubRepositoryRoot(repoRoot);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule stubsMode(StubRunnerProperties.StubsMode stubsMode) {
|
||||
@Override
|
||||
public StubRunnerRule stubsMode(StubRunnerProperties.StubsMode stubsMode) {
|
||||
builder().withStubsMode(stubsMode);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public PortStubRunnerRule downloadStub(String groupId, String artifactId,
|
||||
@Override
|
||||
public PortStubRunnerRule downloadStub(String groupId, String artifactId,
|
||||
String version, String classifier) {
|
||||
builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version + DELIMITER + classifier);
|
||||
builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version
|
||||
+ DELIMITER + classifier);
|
||||
return new PortStubRunnerRule(this.delegate);
|
||||
}
|
||||
|
||||
@Override public PortStubRunnerRule downloadLatestStub(String groupId, String artifactId,
|
||||
@Override
|
||||
public PortStubRunnerRule downloadLatestStub(String groupId, String artifactId,
|
||||
String classifier) {
|
||||
builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + LATEST_VERSION + DELIMITER + classifier);
|
||||
builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + LATEST_VERSION
|
||||
+ DELIMITER + classifier);
|
||||
return new PortStubRunnerRule(this.delegate);
|
||||
}
|
||||
|
||||
@Override public PortStubRunnerRule downloadStub(String groupId, String artifactId,
|
||||
@Override
|
||||
public PortStubRunnerRule downloadStub(String groupId, String artifactId,
|
||||
String version) {
|
||||
builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version);
|
||||
return new PortStubRunnerRule(this.delegate);
|
||||
}
|
||||
|
||||
@Override public PortStubRunnerRule downloadStub(String groupId, String artifactId) {
|
||||
@Override
|
||||
public PortStubRunnerRule downloadStub(String groupId, String artifactId) {
|
||||
builder().withStubs(groupId + DELIMITER + artifactId);
|
||||
return new PortStubRunnerRule(this.delegate);
|
||||
}
|
||||
|
||||
@Override public PortStubRunnerRule downloadStub(String ivyNotation) {
|
||||
@Override
|
||||
public PortStubRunnerRule downloadStub(String ivyNotation) {
|
||||
builder().withStubs(ivyNotation);
|
||||
return new PortStubRunnerRule(this.delegate);
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule downloadStubs(String... ivyNotations) {
|
||||
@Override
|
||||
public StubRunnerRule downloadStubs(String... ivyNotations) {
|
||||
builder().withStubs(Arrays.asList(ivyNotations));
|
||||
return new PortStubRunnerRule(this.delegate);
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule downloadStubs(List<String> ivyNotations) {
|
||||
@Override
|
||||
public StubRunnerRule downloadStubs(List<String> ivyNotations) {
|
||||
builder().withStubs(ivyNotations);
|
||||
return new PortStubRunnerRule(this.delegate);
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule withStubPerConsumer(boolean stubPerConsumer) {
|
||||
@Override
|
||||
public StubRunnerRule withStubPerConsumer(boolean stubPerConsumer) {
|
||||
builder().withStubPerConsumer(stubPerConsumer);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule withConsumerName(String consumerName) {
|
||||
@Override
|
||||
public StubRunnerRule withConsumerName(String consumerName) {
|
||||
builder().withConsumerName(consumerName);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule withMappingsOutputFolder(String mappingsOutputFolder) {
|
||||
@Override
|
||||
public StubRunnerRule withMappingsOutputFolder(String mappingsOutputFolder) {
|
||||
builder().withMappingsOutputFolder(mappingsOutputFolder);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule withDeleteStubsAfterTest(
|
||||
boolean deleteStubsAfterTest) {
|
||||
@Override
|
||||
public StubRunnerRule withDeleteStubsAfterTest(boolean deleteStubsAfterTest) {
|
||||
builder().withDeleteStubsAfterTest(deleteStubsAfterTest);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule withProperties(Map<String, String> properties) {
|
||||
@Override
|
||||
public StubRunnerRule withProperties(Map<String, String> properties) {
|
||||
builder().withProperties(properties);
|
||||
return this.delegate;
|
||||
}
|
||||
@@ -189,7 +215,8 @@ public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptio
|
||||
public boolean trigger(String ivyNotation, String labelName) {
|
||||
boolean result = this.stubFinder().trigger(ivyNotation, labelName);
|
||||
if (!result) {
|
||||
throw new IllegalStateException("Failed to trigger a message with notation [" + ivyNotation + "] and label [" + labelName + "]");
|
||||
throw new IllegalStateException("Failed to trigger a message with notation ["
|
||||
+ ivyNotation + "] and label [" + labelName + "]");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -198,7 +225,8 @@ public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptio
|
||||
public boolean trigger(String labelName) {
|
||||
boolean result = this.stubFinder().trigger(labelName);
|
||||
if (!result) {
|
||||
throw new IllegalStateException("Failed to trigger a message with label [" + labelName + "]");
|
||||
throw new IllegalStateException(
|
||||
"Failed to trigger a message with label [" + labelName + "]");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -245,22 +273,26 @@ public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptio
|
||||
|
||||
private static final String EXCEPTION_MESSAGE = "Please provide a custom MessageVerifier to use this feature";
|
||||
|
||||
@Override public void send(Object message, String destination) {
|
||||
@Override
|
||||
public void send(Object message, String destination) {
|
||||
throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
|
||||
}
|
||||
|
||||
@Override public Object receive(String destination, long timeout,
|
||||
TimeUnit timeUnit) {
|
||||
@Override
|
||||
public Object receive(String destination, long timeout, TimeUnit timeUnit) {
|
||||
throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
|
||||
}
|
||||
|
||||
@Override public Object receive(String destination) {
|
||||
@Override
|
||||
public Object receive(String destination) {
|
||||
throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
|
||||
}
|
||||
|
||||
@Override public void send(Object payload, Map headers, String destination) {
|
||||
@Override
|
||||
public void send(Object payload, Map headers, String destination) {
|
||||
throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,15 +300,19 @@ public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptio
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public static class PortStubRunnerRule extends StubRunnerRule implements PortStubRunnerRuleOptions {
|
||||
public static class PortStubRunnerRule extends StubRunnerRule
|
||||
implements PortStubRunnerRuleOptions {
|
||||
|
||||
PortStubRunnerRule(StubRunnerRule delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
@Override public StubRunnerRule withPort(Integer port) {
|
||||
@Override
|
||||
public StubRunnerRule withPort(Integer port) {
|
||||
builder().withPort(port);
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@ import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
|
||||
|
||||
interface StubRunnerRuleOptions {
|
||||
|
||||
/**
|
||||
* Pass the {@link MessageVerifier} that this rule should use.
|
||||
* If you don't pass anything a {@link StubRunnerRule.ExceptionThrowingMessageVerifier} will be used.
|
||||
* That means that an exception will be thrown whenever you try to do sth messaging related.
|
||||
* Pass the {@link MessageVerifier} that this rule should use. If you don't pass
|
||||
* anything a {@link StubRunnerRule.ExceptionThrowingMessageVerifier} will be used.
|
||||
* That means that an exception will be thrown whenever you try to do sth messaging
|
||||
* related.
|
||||
*/
|
||||
StubRunnerRule messageVerifier(MessageVerifier messageVerifier);
|
||||
|
||||
@@ -45,11 +47,12 @@ interface StubRunnerRuleOptions {
|
||||
/**
|
||||
* Group Id, artifact Id, version and classifier of a single stub to download
|
||||
*/
|
||||
PortStubRunnerRuleOptions downloadStub(String groupId, String artifactId, String version,
|
||||
String classifier);
|
||||
PortStubRunnerRuleOptions downloadStub(String groupId, String artifactId,
|
||||
String version, String classifier);
|
||||
|
||||
/**
|
||||
* Group Id, artifact Id and classifier of a single stub to download in the latest version
|
||||
* Group Id, artifact Id and classifier of a single stub to download in the latest
|
||||
* version
|
||||
*/
|
||||
PortStubRunnerRuleOptions downloadLatestStub(String groupId, String artifactId,
|
||||
String classifier);
|
||||
@@ -61,7 +64,8 @@ interface StubRunnerRuleOptions {
|
||||
String version);
|
||||
|
||||
/**
|
||||
* Group Id, artifact Id of a single stub to download. Default classifier will be picked.
|
||||
* Group Id, artifact Id of a single stub to download. Default classifier will be
|
||||
* picked.
|
||||
*/
|
||||
PortStubRunnerRuleOptions downloadStub(String groupId, String artifactId);
|
||||
|
||||
@@ -96,13 +100,15 @@ interface StubRunnerRuleOptions {
|
||||
StubRunnerRule withMappingsOutputFolder(String mappingsOutputFolder);
|
||||
|
||||
/**
|
||||
* If set to {@code false} will NOT delete stubs from a temporary
|
||||
* folder after running tests
|
||||
* If set to {@code false} will NOT delete stubs from a temporary folder after running
|
||||
* tests
|
||||
*/
|
||||
StubRunnerRule withDeleteStubsAfterTest(boolean deleteStubsAfterTest);
|
||||
|
||||
/**
|
||||
* Map of properties that can be passed to custom {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
|
||||
* Map of properties that can be passed to custom
|
||||
* {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
|
||||
*/
|
||||
StubRunnerRule withProperties(Map<String, String> properties);
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
* {@link org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner} by
|
||||
* loading in AutoConfigurations related to Stream and Integration only if the relevant
|
||||
* jars are in classpath.
|
||||
*
|
||||
*
|
||||
* @author Biju Kunjummen
|
||||
*/
|
||||
@Configuration
|
||||
@@ -32,4 +32,5 @@ public class StubRunnerStreamsIntegrationAutoConfiguration {
|
||||
static class IntegrationRelatedAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,22 +46,24 @@ import org.springframework.messaging.Message;
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(IntegrationFlowBuilder.class)
|
||||
@ConditionalOnProperty(name="stubrunner.integration.enabled", havingValue="true", matchIfMissing=true)
|
||||
@ConditionalOnProperty(name = "stubrunner.integration.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class StubRunnerIntegrationConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name="stubFlowRegistrar")
|
||||
@ConditionalOnMissingBean(name = "stubFlowRegistrar")
|
||||
public FlowRegistrar stubFlowRegistrar(AutowireCapableBeanFactory beanFactory,
|
||||
BatchStubRunner batchStubRunner) {
|
||||
Map<StubConfiguration, Collection<Contract>> contracts = batchStubRunner
|
||||
.getContracts();
|
||||
for (Entry<StubConfiguration, Collection<Contract>> entry : contracts.entrySet()) {
|
||||
for (Entry<StubConfiguration, Collection<Contract>> entry : contracts
|
||||
.entrySet()) {
|
||||
String name = entry.getKey().getGroupId() + "_"
|
||||
+ entry.getKey().getArtifactId();
|
||||
for (Contract dsl : entry.getValue()) {
|
||||
if (dsl.getInput() != null && dsl.getInput().getMessageFrom() != null
|
||||
&& dsl.getInput().getMessageFrom().getClientValue() != null) {
|
||||
final String flowName = name + "_" + dsl.getLabel() + "_" + dsl.hashCode();
|
||||
final String flowName = name + "_" + dsl.getLabel() + "_"
|
||||
+ dsl.hashCode();
|
||||
IntegrationFlowBuilder builder = IntegrationFlows
|
||||
.from(dsl.getInput().getMessageFrom().getClientValue())
|
||||
.filter(new StubRunnerIntegrationMessageSelector(dsl),
|
||||
@@ -90,18 +92,22 @@ public class StubRunnerIntegrationConfiguration {
|
||||
beanFactory.getBean(flowName + ".filter", Lifecycle.class).start();
|
||||
beanFactory.getBean(flowName + ".transformer", Lifecycle.class)
|
||||
.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new FlowRegistrar();
|
||||
}
|
||||
|
||||
private static class DummyMessageHandler {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void handle(Message<?> message) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class FlowRegistrar {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import com.toomuchcoding.jsonassert.JsonAssertion;
|
||||
class StubRunnerIntegrationMessageSelector implements MessageSelector {
|
||||
|
||||
private final Contract groovyDsl;
|
||||
|
||||
private final ContractVerifierObjectMapper objectMapper = new ContractVerifierObjectMapper();
|
||||
|
||||
StubRunnerIntegrationMessageSelector(Contract groovyDsl) {
|
||||
@@ -58,7 +59,8 @@ class StubRunnerIntegrationMessageSelector implements MessageSelector {
|
||||
}
|
||||
Object inputMessage = message.getPayload();
|
||||
BodyMatchers matchers = this.groovyDsl.getInput().getBodyMatchers();
|
||||
Object dslBody = MapConverter.getStubSideValues(this.groovyDsl.getInput().getMessageBody());
|
||||
Object dslBody = MapConverter
|
||||
.getStubSideValues(this.groovyDsl.getInput().getMessageBody());
|
||||
Object matchingInputMessage = JsonToJsonPathsConverter
|
||||
.removeMatchingJsonPaths(dslBody, matchers);
|
||||
JsonPaths jsonPaths = JsonToJsonPathsConverter
|
||||
@@ -66,7 +68,8 @@ class StubRunnerIntegrationMessageSelector implements MessageSelector {
|
||||
matchingInputMessage);
|
||||
DocumentContext parsedJson;
|
||||
try {
|
||||
parsedJson = JsonPath.parse(this.objectMapper.writeValueAsString(inputMessage));
|
||||
parsedJson = JsonPath
|
||||
.parse(this.objectMapper.writeValueAsString(inputMessage));
|
||||
}
|
||||
catch (JsonProcessingException e) {
|
||||
throw new IllegalStateException("Cannot serialize to JSON", e);
|
||||
@@ -77,7 +80,8 @@ class StubRunnerIntegrationMessageSelector implements MessageSelector {
|
||||
}
|
||||
if (matchers != null && matchers.hasMatchers()) {
|
||||
for (BodyMatcher matcher : matchers.jsonPathMatchers()) {
|
||||
String jsonPath = JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher, dslBody);
|
||||
String jsonPath = JsonToJsonPathsConverter
|
||||
.convertJsonPathAndRegexToAJsonPath(matcher, dslBody);
|
||||
matches &= matchesJsonPath(parsedJson, jsonPath);
|
||||
}
|
||||
}
|
||||
@@ -86,8 +90,7 @@ class StubRunnerIntegrationMessageSelector implements MessageSelector {
|
||||
|
||||
private boolean matchesJsonPath(DocumentContext parsedJson, String jsonPath) {
|
||||
try {
|
||||
JsonAssertion.assertThat(parsedJson)
|
||||
.matchesJsonPath(jsonPath);
|
||||
JsonAssertion.assertThat(parsedJson).matchesJsonPath(jsonPath);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -102,10 +105,11 @@ class StubRunnerIntegrationMessageSelector implements MessageSelector {
|
||||
String name = it.getName();
|
||||
Object value = it.getClientValue();
|
||||
Object valueInHeader = headers.get(name);
|
||||
matches &= value instanceof Pattern ?
|
||||
((Pattern) value).matcher(valueInHeader.toString()).matches() :
|
||||
valueInHeader!=null && valueInHeader.equals(value);
|
||||
matches &= value instanceof Pattern
|
||||
? ((Pattern) value).matcher(valueInHeader.toString()).matches()
|
||||
: valueInHeader != null && valueInHeader.equals(value);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ import org.springframework.messaging.support.MessageBuilder;
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class StubRunnerIntegrationTransformer implements GenericTransformer<Message<?>, Message<?>> {
|
||||
class StubRunnerIntegrationTransformer
|
||||
implements GenericTransformer<Message<?>, Message<?>> {
|
||||
|
||||
private final Contract groovyDsl;
|
||||
|
||||
@@ -43,8 +44,11 @@ class StubRunnerIntegrationTransformer implements GenericTransformer<Message<?>,
|
||||
if (this.groovyDsl.getOutputMessage() == null) {
|
||||
return source;
|
||||
}
|
||||
String payload = BodyExtractor.extractStubValueFrom(this.groovyDsl.getOutputMessage().getBody());
|
||||
Map<String, Object> headers = this.groovyDsl.getOutputMessage().getHeaders().asStubSideMap();
|
||||
String payload = BodyExtractor
|
||||
.extractStubValueFrom(this.groovyDsl.getOutputMessage().getBody());
|
||||
Map<String, Object> headers = this.groovyDsl.getOutputMessage().getHeaders()
|
||||
.asStubSideMap();
|
||||
return MessageBuilder.createMessage(payload, new MessageHeaders(headers));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,15 +55,15 @@ import org.springframework.util.StringUtils;
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({IntegrationFlows.class, EnableBinding.class})
|
||||
@ConditionalOnProperty(name="stubrunner.stream.enabled", havingValue="true", matchIfMissing=true)
|
||||
@ConditionalOnClass({ IntegrationFlows.class, EnableBinding.class })
|
||||
@ConditionalOnProperty(name = "stubrunner.stream.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@AutoConfigureBefore(StubRunnerIntegrationConfiguration.class)
|
||||
public class StubRunnerStreamConfiguration {
|
||||
|
||||
private static final Log log = LogFactory.getLog(StubRunnerStreamConfiguration.class);
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name="stubFlowRegistrar")
|
||||
@ConditionalOnMissingBean(name = "stubFlowRegistrar")
|
||||
@ConditionalOnBean(BindingServiceProperties.class)
|
||||
public FlowRegistrar stubFlowRegistrar(AutowireCapableBeanFactory beanFactory,
|
||||
BatchStubRunner batchStubRunner) {
|
||||
@@ -78,10 +78,9 @@ public class StubRunnerStreamConfiguration {
|
||||
if (dsl == null) {
|
||||
continue;
|
||||
}
|
||||
if (dsl.getInput() != null
|
||||
&& dsl.getInput().getMessageFrom() != null
|
||||
&& StringUtils.hasText(
|
||||
dsl.getInput().getMessageFrom().getClientValue())) {
|
||||
if (dsl.getInput() != null && dsl.getInput().getMessageFrom() != null
|
||||
&& StringUtils.hasText(
|
||||
dsl.getInput().getMessageFrom().getClientValue())) {
|
||||
final String flowName = name + "_" + dsl.getLabel() + "_"
|
||||
+ dsl.hashCode();
|
||||
String from = resolvedDestination(beanFactory,
|
||||
@@ -111,16 +110,18 @@ public class StubRunnerStreamConfiguration {
|
||||
builder = builder.handle(new DummyMessageHandler(), "handle");
|
||||
}
|
||||
beanFactory.initializeBean(builder.get(), flowName);
|
||||
beanFactory.getBean(flowName + ".filter", Lifecycle.class)
|
||||
.start();
|
||||
beanFactory.getBean(flowName + ".filter", Lifecycle.class).start();
|
||||
beanFactory.getBean(flowName + ".transformer", Lifecycle.class)
|
||||
.start();
|
||||
} else if (dsl.getOutputMessage() != null
|
||||
}
|
||||
else if (dsl.getOutputMessage() != null
|
||||
&& dsl.getOutputMessage().getSentTo() != null
|
||||
&& StringUtils.hasText(
|
||||
dsl.getOutputMessage().getSentTo().getClientValue())) {
|
||||
BinderAwareChannelResolver resolver = beanFactory.getBean(BinderAwareChannelResolver.class);
|
||||
resolver.resolveDestination(dsl.getOutputMessage().getSentTo().getClientValue());
|
||||
dsl.getOutputMessage().getSentTo().getClientValue())) {
|
||||
BinderAwareChannelResolver resolver = beanFactory
|
||||
.getBean(BinderAwareChannelResolver.class);
|
||||
resolver.resolveDestination(
|
||||
dsl.getOutputMessage().getSentTo().getClientValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,26 +134,33 @@ public class StubRunnerStreamConfiguration {
|
||||
for (Map.Entry<String, BindingProperties> entry : bindings.entrySet()) {
|
||||
if (destination.equals(entry.getValue().getDestination())) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Found a channel named [" + entry.getKey() + "] with destination [" + destination + "]");
|
||||
log.debug("Found a channel named [" + entry.getKey()
|
||||
+ "] with destination [" + destination + "]");
|
||||
}
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(
|
||||
"No destination named [" + destination + "] was found. Assuming that the destination equals the channel name");
|
||||
log.debug("No destination named [" + destination
|
||||
+ "] was found. Assuming that the destination equals the channel name");
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
private Map<String, BindingProperties> bindingProperties(AutowireCapableBeanFactory context) {
|
||||
private Map<String, BindingProperties> bindingProperties(
|
||||
AutowireCapableBeanFactory context) {
|
||||
return context.getBean(BindingServiceProperties.class).getBindings();
|
||||
}
|
||||
|
||||
private static class DummyMessageHandler {
|
||||
public void handle(Message<?> message) {}
|
||||
|
||||
public void handle(Message<?> message) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class FlowRegistrar {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,9 +48,11 @@ import com.toomuchcoding.jsonassert.JsonAssertion;
|
||||
*/
|
||||
class StubRunnerStreamMessageSelector implements MessageSelector {
|
||||
|
||||
private static final Log log = LogFactory.getLog(StubRunnerStreamMessageSelector.class);
|
||||
private static final Log log = LogFactory
|
||||
.getLog(StubRunnerStreamMessageSelector.class);
|
||||
|
||||
private final Contract groovyDsl;
|
||||
|
||||
private final ContractVerifierObjectMapper objectMapper = new ContractVerifierObjectMapper();
|
||||
|
||||
StubRunnerStreamMessageSelector(Contract groovyDsl) {
|
||||
@@ -62,13 +64,15 @@ class StubRunnerStreamMessageSelector implements MessageSelector {
|
||||
List<String> unmatchedHeaders = headersMatch(message);
|
||||
if (!unmatchedHeaders.isEmpty()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Contract [" + this.groovyDsl + "] hasn't matched the following headers " + unmatchedHeaders);
|
||||
log.debug("Contract [" + this.groovyDsl
|
||||
+ "] hasn't matched the following headers " + unmatchedHeaders);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Object inputMessage = message.getPayload();
|
||||
BodyMatchers matchers = this.groovyDsl.getInput().getBodyMatchers();
|
||||
Object dslBody = MapConverter.getStubSideValues(this.groovyDsl.getInput().getMessageBody());
|
||||
Object dslBody = MapConverter
|
||||
.getStubSideValues(this.groovyDsl.getInput().getMessageBody());
|
||||
Object matchingInputMessage = JsonToJsonPathsConverter
|
||||
.removeMatchingJsonPaths(dslBody, matchers);
|
||||
JsonPaths jsonPaths = JsonToJsonPathsConverter
|
||||
@@ -76,7 +80,8 @@ class StubRunnerStreamMessageSelector implements MessageSelector {
|
||||
matchingInputMessage);
|
||||
DocumentContext parsedJson;
|
||||
try {
|
||||
parsedJson = JsonPath.parse(this.objectMapper.writeValueAsString(inputMessage));
|
||||
parsedJson = JsonPath
|
||||
.parse(this.objectMapper.writeValueAsString(inputMessage));
|
||||
}
|
||||
catch (JsonProcessingException e) {
|
||||
throw new IllegalStateException("Cannot serialize to JSON", e);
|
||||
@@ -88,23 +93,27 @@ class StubRunnerStreamMessageSelector implements MessageSelector {
|
||||
}
|
||||
if (matchers != null && matchers.hasMatchers()) {
|
||||
for (BodyMatcher matcher : matchers.jsonPathMatchers()) {
|
||||
String jsonPath = JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher, dslBody);
|
||||
String jsonPath = JsonToJsonPathsConverter
|
||||
.convertJsonPathAndRegexToAJsonPath(matcher, dslBody);
|
||||
matches &= matchesJsonPath(unmatchedJsonPath, parsedJson, jsonPath);
|
||||
}
|
||||
}
|
||||
if (!unmatchedJsonPath.isEmpty()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Contract [" + this.groovyDsl + "] didn't much the body due to " + unmatchedJsonPath);
|
||||
log.debug("Contract [" + this.groovyDsl + "] didn't much the body due to "
|
||||
+ unmatchedJsonPath);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private boolean matchesJsonPath(List<String> unmatchedJsonPath, DocumentContext parsedJson, String jsonPath) {
|
||||
private boolean matchesJsonPath(List<String> unmatchedJsonPath,
|
||||
DocumentContext parsedJson, String jsonPath) {
|
||||
try {
|
||||
JsonAssertion.assertThat(parsedJson).matchesJsonPath(jsonPath);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
unmatchedJsonPath.add(e.getLocalizedMessage());
|
||||
return false;
|
||||
}
|
||||
@@ -121,20 +130,25 @@ class StubRunnerStreamMessageSelector implements MessageSelector {
|
||||
if (value instanceof Pattern) {
|
||||
Pattern pattern = (Pattern) value;
|
||||
matches = pattern.matcher(valueInHeader.toString()).matches();
|
||||
} else {
|
||||
matches = valueInHeader != null && valueInHeader.toString().equals(value.toString());
|
||||
}
|
||||
else {
|
||||
matches = valueInHeader != null
|
||||
&& valueInHeader.toString().equals(value.toString());
|
||||
}
|
||||
if (!matches) {
|
||||
unmatchedHeaders.add("Header with name [" + name + "] was supposed to " +
|
||||
unmatchedText(value) + " but the value is [" + (valueInHeader != null ?
|
||||
valueInHeader.toString() : "null") + "]");
|
||||
unmatchedHeaders.add("Header with name [" + name + "] was supposed to "
|
||||
+ unmatchedText(value) + " but the value is ["
|
||||
+ (valueInHeader != null ? valueInHeader.toString() : "null")
|
||||
+ "]");
|
||||
}
|
||||
}
|
||||
return unmatchedHeaders;
|
||||
}
|
||||
|
||||
private String unmatchedText(Object expectedValue) {
|
||||
return expectedValue instanceof Pattern ? "match pattern [" + ((Pattern) expectedValue).pattern() + "]" :
|
||||
"be equal to [" + expectedValue + "]";
|
||||
return expectedValue instanceof Pattern
|
||||
? "match pattern [" + ((Pattern) expectedValue).pattern() + "]"
|
||||
: "be equal to [" + expectedValue + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,11 +40,15 @@ class StubRunnerStreamTransformer implements GenericTransformer<Message<?>, Mess
|
||||
|
||||
@Override
|
||||
public Message<?> transform(Message<?> source) {
|
||||
if (this.groovyDsl.getOutputMessage()==null) {
|
||||
if (this.groovyDsl.getOutputMessage() == null) {
|
||||
return source;
|
||||
}
|
||||
String payload = BodyExtractor.extractStubValueFrom(this.groovyDsl.getOutputMessage().getBody());
|
||||
Map<String, Object> headers = this.groovyDsl.getOutputMessage().getHeaders().asStubSideMap();
|
||||
return MessageBuilder.createMessage(payload.getBytes(), new MessageHeaders(headers));
|
||||
String payload = BodyExtractor
|
||||
.extractStubValueFrom(this.groovyDsl.getOutputMessage().getBody());
|
||||
Map<String, Object> headers = this.groovyDsl.getOutputMessage().getHeaders()
|
||||
.asStubSideMap();
|
||||
return MessageBuilder.createMessage(payload.getBytes(),
|
||||
new MessageHeaders(headers));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,46 +20,59 @@ import org.springframework.web.client.RestTemplate;
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.2.6
|
||||
*/
|
||||
public final class StubRunnerWireMockTestExecutionListener extends AbstractTestExecutionListener {
|
||||
public final class StubRunnerWireMockTestExecutionListener
|
||||
extends AbstractTestExecutionListener {
|
||||
|
||||
private static final Log log = LogFactory.getLog(StubRunnerWireMockTestExecutionListener.class);
|
||||
private static final Log log = LogFactory
|
||||
.getLog(StubRunnerWireMockTestExecutionListener.class);
|
||||
|
||||
private static Map<ApplicationContext, Map<WireMockHttpServerStub, PortAndMappings>> STUBS = new ConcurrentHashMap<>();
|
||||
|
||||
@Override public void beforeTestClass(TestContext testContext) {
|
||||
@Override
|
||||
public void beforeTestClass(TestContext testContext) {
|
||||
Map<WireMockHttpServerStub, PortAndMappings> stubs = STUBS
|
||||
.get(testContext.getApplicationContext());
|
||||
if (stubs != null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Found a matching application context from [" + testContext.getTestClass().getName() + "]");
|
||||
log.debug("Found a matching application context from ["
|
||||
+ testContext.getTestClass().getName() + "]");
|
||||
}
|
||||
for (Map.Entry<WireMockHttpServerStub, PortAndMappings> entry : stubs.entrySet()) {
|
||||
for (Map.Entry<WireMockHttpServerStub, PortAndMappings> entry : stubs
|
||||
.entrySet()) {
|
||||
while (entry.getKey().isRunning()) {
|
||||
entry.getKey().stop();
|
||||
}
|
||||
List<StubMapping> mappings = entry.getValue().mappings;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Stopped a running WireMock instance at "
|
||||
+ "port [" + entry.getValue().port + "] with stub mappings "
|
||||
+ "size [" + mappings.size() + "]. Restarting the stub.");
|
||||
log.debug("Stopped a running WireMock instance at " + "port ["
|
||||
+ entry.getValue().port + "] with stub mappings " + "size ["
|
||||
+ mappings.size() + "]. Restarting the stub.");
|
||||
}
|
||||
entry.getKey().start(entry.getValue().port);
|
||||
entry.getKey().registerDescriptors(mappings);
|
||||
/*
|
||||
Thanks to Tom Akehurst:
|
||||
I looked at tcpdump while running the failing test. HttpUrlConnection is doing something weird - it's creating a connection in a
|
||||
previous test case, which works fine, then the usual fin -> fin ack etc. etc. ending handshake happens. But it seems it
|
||||
isn't discarded, but reused after that. Because the server thinks (rightly) that the connection is closed, it just sends a RST packet.
|
||||
Calling the admin endpoint just happened to remove the dead connection from the pool.
|
||||
This also fixes the problem (which using the Java HTTP client): System.setProperty("http.keepAlive", "false");
|
||||
* Thanks to Tom Akehurst: I looked at tcpdump while running the failing
|
||||
* test. HttpUrlConnection is doing something weird - it's creating a
|
||||
* connection in a previous test case, which works fine, then the usual
|
||||
* fin -> fin ack etc. etc. ending handshake happens. But it seems it
|
||||
* isn't discarded, but reused after that. Because the server thinks
|
||||
* (rightly) that the connection is closed, it just sends a RST packet.
|
||||
* Calling the admin endpoint just happened to remove the dead connection
|
||||
* from the pool. This also fixes the problem (which using the Java HTTP
|
||||
* client): System.setProperty("http.keepAlive", "false");
|
||||
*/
|
||||
Assert.isTrue(new RestTemplate().getForEntity("http://localhost:" + entry.getValue().port + "/__admin/mappings", String.class)
|
||||
.getStatusCode().is2xxSuccessful(), "__admin/mappings endpoint wasn't accessible");
|
||||
Assert.isTrue(
|
||||
new RestTemplate()
|
||||
.getForEntity("http://localhost:" + entry.getValue().port
|
||||
+ "/__admin/mappings", String.class)
|
||||
.getStatusCode().is2xxSuccessful(),
|
||||
"__admin/mappings endpoint wasn't accessible");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void afterTestClass(TestContext testContext) {
|
||||
@Override
|
||||
public void afterTestClass(TestContext testContext) {
|
||||
STUBS.put(testContext.getApplicationContext(), WireMockHttpServerStub.SERVERS);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Stopping servers " + WireMockHttpServerStub.SERVERS);
|
||||
@@ -68,4 +81,5 @@ public final class StubRunnerWireMockTestExecutionListener extends AbstractTestE
|
||||
serverStub.stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,9 +50,9 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
private WireMockServer wireMockServer;
|
||||
|
||||
private WireMockConfiguration config() {
|
||||
if (ClassUtils.isPresent("org.springframework.cloud.contract.wiremock.WireMockSpring", null)) {
|
||||
return WireMockSpring.options()
|
||||
.extensions(responseTransformers());
|
||||
if (ClassUtils.isPresent(
|
||||
"org.springframework.cloud.contract.wiremock.WireMockSpring", null)) {
|
||||
return WireMockSpring.options().extensions(responseTransformers());
|
||||
}
|
||||
return new WireMockConfiguration().extensions(responseTransformers());
|
||||
}
|
||||
@@ -65,7 +65,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
for (WireMockExtensions wireMockExtension : wireMockExtensions) {
|
||||
extensions.addAll(wireMockExtension.extensions());
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
extensions.add(new DefaultResponseTransformer(false, helpers()));
|
||||
}
|
||||
return extensions.toArray(new Extension[extensions.size()]);
|
||||
@@ -73,9 +74,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
|
||||
/**
|
||||
* Override this if you want to register your own helpers
|
||||
*
|
||||
* @deprecated - please use the {@link WireMockExtensions} mechanism and pass
|
||||
* the helpers in your implementation
|
||||
* @deprecated - please use the {@link WireMockExtensions} mechanism and pass the
|
||||
* helpers in your implementation
|
||||
*/
|
||||
@Deprecated
|
||||
protected Map<String, Helper> helpers() {
|
||||
@@ -108,8 +108,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
|
||||
@Override
|
||||
public HttpServerStub start(int port) {
|
||||
this.wireMockServer = new WireMockServer(config().port(port)
|
||||
.notifier(new Slf4jNotifier(true)));
|
||||
this.wireMockServer = new WireMockServer(
|
||||
config().port(port).notifier(new Slf4jNotifier(true)));
|
||||
this.wireMockServer.start();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Started WireMock at port [" + port + "]");
|
||||
@@ -141,7 +141,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public String registeredMappings() {
|
||||
@Override
|
||||
public String registeredMappings() {
|
||||
Collection<String> mappings = new ArrayList<>();
|
||||
for (StubMapping stubMapping : this.wireMockServer.getStubMappings()) {
|
||||
mappings.add(stubMapping.toString());
|
||||
@@ -189,12 +190,14 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
try {
|
||||
stubMappings.add(registerDescriptor(wireMock, mappingDescriptor));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Registered stub mappings from [" + mappingDescriptor + "]");
|
||||
log.debug(
|
||||
"Registered stub mappings from [" + mappingDescriptor + "]");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to register the stub mapping [" + mappingDescriptor + "]", e);
|
||||
log.debug("Failed to register the stub mapping [" + mappingDescriptor
|
||||
+ "]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,7 +213,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
|
||||
void registerDescriptors(List<StubMapping> stubMappings) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Registering stub mappings size [" + stubMappings.size() + "] at port [" + port() + "]");
|
||||
log.debug("Registering stub mappings size [" + stubMappings.size()
|
||||
+ "] at port [" + port() + "]");
|
||||
}
|
||||
for (StubMapping mapping : stubMappings) {
|
||||
wireMock().register(mapping);
|
||||
@@ -222,13 +226,16 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
}
|
||||
|
||||
private void registerHealthCheck(WireMock wireMock, String url, String body) {
|
||||
wireMock.register(
|
||||
WireMock.get(WireMock.urlEqualTo(url)).willReturn(WireMock.aResponse().withBody(body).withStatus(200)));
|
||||
wireMock.register(WireMock.get(WireMock.urlEqualTo(url))
|
||||
.willReturn(WireMock.aResponse().withBody(body).withStatus(200)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PortAndMappings {
|
||||
|
||||
final Integer port;
|
||||
|
||||
final List<StubMapping> mappings;
|
||||
|
||||
PortAndMappings(Integer port, List<StubMapping> mappings) {
|
||||
@@ -236,7 +243,10 @@ class PortAndMappings {
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "PortAndMappings{" + "port=" + this.port + ", mappings=" + this.mappings.size() + '}';
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PortAndMappings{" + "port=" + this.port + ", mappings="
|
||||
+ this.mappings.size() + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,7 +34,8 @@ import org.springframework.context.annotation.Import;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@Import({HttpStubsController.class, TriggerController.class, StubRunnerConfiguration.class})
|
||||
@Import({ HttpStubsController.class, TriggerController.class,
|
||||
StubRunnerConfiguration.class })
|
||||
public @interface EnableStubRunnerServer {
|
||||
|
||||
}
|
||||
|
||||
@@ -49,9 +49,10 @@ public class HttpStubsController {
|
||||
@RequestMapping(path = "/{ivy:.*}")
|
||||
public ResponseEntity<Integer> consumer(@PathVariable String ivy) {
|
||||
Integer port = this.stubRunning.runStubs().getPort(ivy);
|
||||
if (port!=null) {
|
||||
if (port != null) {
|
||||
return ResponseEntity.ok(port);
|
||||
}
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -49,22 +49,32 @@ public class TriggerController {
|
||||
}
|
||||
|
||||
@PostMapping("/{label:.*}")
|
||||
public ResponseEntity<Map<String, Collection<String>>> trigger(@PathVariable String label) {
|
||||
public ResponseEntity<Map<String, Collection<String>>> trigger(
|
||||
@PathVariable String label) {
|
||||
try {
|
||||
this.stubFinder.trigger(label);
|
||||
return ResponseEntity.ok().body(Collections.<String, Collection<String>>emptyMap());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Exception occurred while trying to return [" + label + "] label. \n\nAvailable labels are [" + this.stubFinder.labels() +" ]", e);
|
||||
return ResponseEntity.ok()
|
||||
.body(Collections.<String, Collection<String>>emptyMap());
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Exception occurred while trying to return ["
|
||||
+ label + "] label. \n\nAvailable labels are ["
|
||||
+ this.stubFinder.labels() + " ]", e);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{ivyNotation:.*}/{label:.*}")
|
||||
public ResponseEntity<Map<String, Collection<String>>> triggerByArtifact(@PathVariable String ivyNotation, @PathVariable String label) {
|
||||
public ResponseEntity<Map<String, Collection<String>>> triggerByArtifact(
|
||||
@PathVariable String ivyNotation, @PathVariable String label) {
|
||||
try {
|
||||
this.stubFinder.trigger(ivyNotation, label);
|
||||
return ResponseEntity.ok().body(Collections.<String, Collection<String>>emptyMap());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Exception occurred while trying to return [" + label + "] label. \n\nAvailable labels are [" + this.stubFinder.labels() +" ]", e);
|
||||
return ResponseEntity.ok()
|
||||
.body(Collections.<String, Collection<String>>emptyMap());
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Exception occurred while trying to return ["
|
||||
+ label + "] label. \n\nAvailable labels are ["
|
||||
+ this.stubFinder.labels() + " ]", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,8 +55,9 @@ public @interface AutoConfigureStubRunner {
|
||||
String repositoryRoot() default "";
|
||||
|
||||
/**
|
||||
* The ids of the stubs to run in "ivy" notation ([groupId]:artifactId[:version][:classifier][:port]).
|
||||
* {@code groupId}, {@code version}, {@code classifier} and {@code port} can be optional.
|
||||
* The ids of the stubs to run in "ivy" notation
|
||||
* ([groupId]:artifactId[:version][:classifier][:port]). {@code groupId},
|
||||
* {@code version}, {@code classifier} and {@code port} can be optional.
|
||||
*/
|
||||
String[] ids() default {};
|
||||
|
||||
@@ -66,39 +67,50 @@ public @interface AutoConfigureStubRunner {
|
||||
String classifier() default "stubs";
|
||||
|
||||
/**
|
||||
* On the producer side the consumers can have a folder that contains contracts related only to them. By setting the flag to {@code true}
|
||||
* we no longer register all stubs but only those that correspond to the consumer application's name. In other words
|
||||
* we'll scan the path of every stub and if it contains the name of the consumer in the path only then will it get registered.
|
||||
* On the producer side the consumers can have a folder that contains contracts
|
||||
* related only to them. By setting the flag to {@code true} we no longer register all
|
||||
* stubs but only those that correspond to the consumer application's name. In other
|
||||
* words we'll scan the path of every stub and if it contains the name of the consumer
|
||||
* in the path only then will it get registered.
|
||||
*
|
||||
* Let's look at this example. Let's assume
|
||||
* that we have a producer called {@code foo} and two consumers {@code baz} and {@code bar}. On the {@code foo} producer side the
|
||||
* Let's look at this example. Let's assume that we have a producer called {@code foo}
|
||||
* and two consumers {@code baz} and {@code bar}. On the {@code foo} producer side the
|
||||
* contracts would look like this
|
||||
* {@code src/test/resources/contracts/baz-service/some/contracts/...} and
|
||||
* {@code src/test/resources/contracts/bar-service/some/contracts/...}.
|
||||
*
|
||||
* Then when the consumer with {@code spring.application.name} or the {@link AutoConfigureStubRunner#consumerName()}
|
||||
* annotation parameter set to {@code baz-service} will define the test setup as follows
|
||||
* {@code @AutoConfigureStubRunner(ids = "com.example:foo:+:stubs:8095", stubsPerConsumer=true)} then only the stubs registered
|
||||
* under {@code src/test/resources/contracts/baz-service/some/contracts/...} will get registered and those under
|
||||
* {@code src/test/resources/contracts/bar-service/some/contracts/...} will get ignored.
|
||||
* Then when the consumer with {@code spring.application.name} or the
|
||||
* {@link AutoConfigureStubRunner#consumerName()} annotation parameter set to
|
||||
* {@code baz-service} will define the test setup as follows
|
||||
* {@code @AutoConfigureStubRunner(ids = "com.example:foo:+:stubs:8095", stubsPerConsumer=true)}
|
||||
* then only the stubs registered under
|
||||
* {@code src/test/resources/contracts/baz-service/some/contracts/...} will get
|
||||
* registered and those under
|
||||
* {@code src/test/resources/contracts/bar-service/some/contracts/...} will get
|
||||
* ignored.
|
||||
*
|
||||
* @see <a href="https://github.com/spring-cloud/spring-cloud-contract/issues/224">issue 224</a>
|
||||
* @see <a href=
|
||||
* "https://github.com/spring-cloud/spring-cloud-contract/issues/224">issue 224</a>
|
||||
*
|
||||
*/
|
||||
boolean stubsPerConsumer() default false;
|
||||
|
||||
/**
|
||||
* You can override the default {@code spring.application.name} of this field by setting a value to this parameter.
|
||||
* You can override the default {@code spring.application.name} of this field by
|
||||
* setting a value to this parameter.
|
||||
*
|
||||
* @see <a href="https://github.com/spring-cloud/spring-cloud-contract/issues/224">issue 224</a>
|
||||
* @see <a href=
|
||||
* "https://github.com/spring-cloud/spring-cloud-contract/issues/224">issue 224</a>
|
||||
*/
|
||||
String consumerName() default "";
|
||||
|
||||
/**
|
||||
* For debugging purposes you can output the registered mappings to a given folder. Each HTTP server
|
||||
* stub will have its own subfolder where all the mappings will get stored.
|
||||
* For debugging purposes you can output the registered mappings to a given folder.
|
||||
* Each HTTP server stub will have its own subfolder where all the mappings will get
|
||||
* stored.
|
||||
*
|
||||
* @see <a href="https://github.com/spring-cloud/spring-cloud-contract/issues/355">issue 355</a>
|
||||
* @see <a href=
|
||||
* "https://github.com/spring-cloud/spring-cloud-contract/issues/355">issue 355</a>
|
||||
*/
|
||||
String mappingsOutputFolder() default "";
|
||||
|
||||
@@ -114,4 +126,5 @@ public @interface AutoConfigureStubRunner {
|
||||
* @return the properties to add
|
||||
*/
|
||||
String[] properties() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -54,9 +54,12 @@ public class StubRunnerConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private MessageVerifier<?> contractVerifierMessaging;
|
||||
|
||||
private StubDownloaderBuilderProvider provider = new StubDownloaderBuilderProvider();
|
||||
|
||||
@Autowired
|
||||
private StubRunnerProperties props;
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
@@ -84,18 +87,17 @@ public class StubRunnerConfiguration {
|
||||
|
||||
private StubRunnerOptionsBuilder builder() throws IOException {
|
||||
return new StubRunnerOptionsBuilder()
|
||||
.withMinMaxPort(this.props.getMinPort(), this.props.getMaxPort())
|
||||
.withStubRepositoryRoot(this.props.getRepositoryRoot())
|
||||
.withStubsMode(this.props.getStubsMode())
|
||||
.withStubsClassifier(this.props.getClassifier())
|
||||
.withStubs(this.props.getIds())
|
||||
.withUsername(this.props.getUsername())
|
||||
.withPassword(this.props.getPassword())
|
||||
.withStubPerConsumer(this.props.isStubsPerConsumer())
|
||||
.withConsumerName(consumerName())
|
||||
.withMappingsOutputFolder(this.props.getMappingsOutputFolder())
|
||||
.withDeleteStubsAfterTest(this.props.isDeleteStubsAfterTest())
|
||||
.withProperties(this.props.getProperties());
|
||||
.withMinMaxPort(this.props.getMinPort(), this.props.getMaxPort())
|
||||
.withStubRepositoryRoot(this.props.getRepositoryRoot())
|
||||
.withStubsMode(this.props.getStubsMode())
|
||||
.withStubsClassifier(this.props.getClassifier())
|
||||
.withStubs(this.props.getIds()).withUsername(this.props.getUsername())
|
||||
.withPassword(this.props.getPassword())
|
||||
.withStubPerConsumer(this.props.isStubsPerConsumer())
|
||||
.withConsumerName(consumerName())
|
||||
.withMappingsOutputFolder(this.props.getMappingsOutputFolder())
|
||||
.withDeleteStubsAfterTest(this.props.isDeleteStubsAfterTest())
|
||||
.withProperties(this.props.getProperties());
|
||||
}
|
||||
|
||||
private String consumerName() {
|
||||
@@ -108,15 +110,19 @@ public class StubRunnerConfiguration {
|
||||
private void registerPort(RunningStubs runStubs) {
|
||||
MutablePropertySources propertySources = this.environment.getPropertySources();
|
||||
if (!propertySources.contains(STUBRUNNER_PREFIX)) {
|
||||
propertySources.addFirst(
|
||||
new MapPropertySource(STUBRUNNER_PREFIX, new HashMap<String, Object>()));
|
||||
propertySources.addFirst(new MapPropertySource(STUBRUNNER_PREFIX,
|
||||
new HashMap<String, Object>()));
|
||||
}
|
||||
Map<String, Object> source = ((MapPropertySource) propertySources
|
||||
.get(STUBRUNNER_PREFIX)).getSource();
|
||||
for (Map.Entry<StubConfiguration, Integer> entry : runStubs.validNamesAndPorts().entrySet()) {
|
||||
source.put(STUBRUNNER_PREFIX + "." + entry.getKey().getArtifactId() + ".port", entry.getValue());
|
||||
// there are projects where artifact id is the same, what differs is the group id
|
||||
source.put(STUBRUNNER_PREFIX + "." + entry.getKey().getGroupId() + "." + entry.getKey().getArtifactId() + ".port", entry.getValue());
|
||||
for (Map.Entry<StubConfiguration, Integer> entry : runStubs.validNamesAndPorts()
|
||||
.entrySet()) {
|
||||
source.put(STUBRUNNER_PREFIX + "." + entry.getKey().getArtifactId() + ".port",
|
||||
entry.getValue());
|
||||
// there are projects where artifact id is the same, what differs is the group
|
||||
// id
|
||||
source.put(STUBRUNNER_PREFIX + "." + entry.getKey().getGroupId() + "."
|
||||
+ entry.getKey().getArtifactId() + ".port", entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,12 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The annotated field with this annotation will have the port of a running stub
|
||||
* injected.
|
||||
* The annotated field with this annotation will have the port of a running stub injected.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface StubRunnerPort {
|
||||
|
||||
@@ -21,7 +21,8 @@ class StubRunnerPortBeanPostProcessor implements BeanPostProcessor {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
injectStubRunnerPort(bean);
|
||||
return bean;
|
||||
@@ -29,15 +30,17 @@ class StubRunnerPortBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private void injectStubRunnerPort(Object bean) {
|
||||
Class<?> clazz = bean.getClass();
|
||||
ReflectionUtils.FieldCallback fieldCallback =
|
||||
new StubRunnerPortFieldCallback(this.environment, bean);
|
||||
ReflectionUtils.FieldCallback fieldCallback = new StubRunnerPortFieldCallback(
|
||||
this.environment, bean);
|
||||
ReflectionUtils.doWithFields(clazz, fieldCallback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class StubRunnerPortFieldCallback implements ReflectionUtils.FieldCallback {
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
private final Object bean;
|
||||
|
||||
StubRunnerPortFieldCallback(Environment environment, Object bean) {
|
||||
@@ -45,17 +48,20 @@ class StubRunnerPortFieldCallback implements ReflectionUtils.FieldCallback {
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
@Override public void doWith(Field field)
|
||||
@Override
|
||||
public void doWith(Field field)
|
||||
throws IllegalArgumentException, IllegalAccessException {
|
||||
if (!field.isAnnotationPresent(StubRunnerPort.class)) {
|
||||
return;
|
||||
}
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
String stub = field.getDeclaredAnnotation(StubRunnerPort.class).value();
|
||||
Integer port = this.environment.getProperty(
|
||||
StubRunnerConfiguration.STUBRUNNER_PREFIX + "." + stub.replace(":", ".") + ".port", Integer.class);
|
||||
Integer port = this.environment
|
||||
.getProperty(StubRunnerConfiguration.STUBRUNNER_PREFIX + "."
|
||||
+ stub.replace(":", ".") + ".port", Integer.class);
|
||||
if (port != null) {
|
||||
field.set(this.bean, port);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,8 +49,9 @@ public class StubRunnerProperties {
|
||||
private Resource repositoryRoot;
|
||||
|
||||
/**
|
||||
* The ids of the stubs to run in "ivy" notation ([groupId]:artifactId:[version]:[classifier][:port]).
|
||||
* {@code groupId}, {@code classifier}, {@code version} and {@code port} can be optional.
|
||||
* The ids of the stubs to run in "ivy" notation
|
||||
* ([groupId]:artifactId:[version]:[classifier][:port]). {@code groupId},
|
||||
* {@code classifier}, {@code version} and {@code port} can be optional.
|
||||
*/
|
||||
private String[] ids = new String[0];
|
||||
|
||||
@@ -85,7 +86,8 @@ public class StubRunnerProperties {
|
||||
private boolean stubsPerConsumer;
|
||||
|
||||
/**
|
||||
* You can override the default {@code spring.application.name} of this field by setting a value to this parameter.
|
||||
* You can override the default {@code spring.application.name} of this field by
|
||||
* setting a value to this parameter.
|
||||
*/
|
||||
private String consumerName;
|
||||
|
||||
@@ -100,13 +102,14 @@ public class StubRunnerProperties {
|
||||
private StubsMode stubsMode;
|
||||
|
||||
/**
|
||||
* If set to {@code false} will NOT delete stubs from a temporary
|
||||
* folder after running tests
|
||||
* If set to {@code false} will NOT delete stubs from a temporary folder after running
|
||||
* tests
|
||||
*/
|
||||
private boolean deleteStubsAfterTest = true;
|
||||
|
||||
/**
|
||||
* Map of properties that can be passed to custom {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
|
||||
* Map of properties that can be passed to custom
|
||||
* {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
|
||||
*/
|
||||
private Map<String, String> properties = new HashMap<>();
|
||||
|
||||
@@ -129,6 +132,7 @@ public class StubRunnerProperties {
|
||||
* Fetch the stubs from a remote location
|
||||
*/
|
||||
REMOTE,
|
||||
|
||||
}
|
||||
|
||||
public int getMinPort() {
|
||||
@@ -248,8 +252,8 @@ public class StubRunnerProperties {
|
||||
}
|
||||
|
||||
public void setProperties(String[] properties) {
|
||||
Properties elements = StringUtils
|
||||
.splitArrayElementsIntoProperties(properties, "=");
|
||||
Properties elements = StringUtils.splitArrayElementsIntoProperties(properties,
|
||||
"=");
|
||||
if (elements == null) {
|
||||
return;
|
||||
}
|
||||
@@ -258,13 +262,14 @@ public class StubRunnerProperties {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "StubRunnerProperties{" + "minPort=" + this.minPort + ", maxPort=" + this.maxPort
|
||||
+ ", repositoryRoot=" + this.repositoryRoot
|
||||
+ ", ids=" + Arrays.toString(this.ids) + ", classifier='" + this.classifier + '\''
|
||||
+ ", setStubsPerConsumer='" + this.stubsPerConsumer + "', consumerName='" + this.consumerName + '\''
|
||||
+ ", stubsMode='" + this.stubsMode + '\''
|
||||
+ ", size of properties=" + this.properties.size()
|
||||
+ '}';
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StubRunnerProperties{" + "minPort=" + this.minPort + ", maxPort="
|
||||
+ this.maxPort + ", repositoryRoot=" + this.repositoryRoot + ", ids="
|
||||
+ Arrays.toString(this.ids) + ", classifier='" + this.classifier + '\''
|
||||
+ ", setStubsPerConsumer='" + this.stubsPerConsumer + "', consumerName='"
|
||||
+ this.consumerName + '\'' + ", stubsMode='" + this.stubsMode + '\''
|
||||
+ ", size of properties=" + this.properties.size() + '}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,4 +36,5 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@Documented
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.stubbed.discovery.enabled", havingValue = "false")
|
||||
public @interface ConditionalOnStubbedDiscoveryDisabled {
|
||||
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ import java.lang.annotation.Target;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
|
||||
/**
|
||||
* Conditional that checks if the user turned on the stubbed discovery mode.
|
||||
* The feature is turned on by default.
|
||||
* Conditional that checks if the user turned on the stubbed discovery mode. The feature
|
||||
* is turned on by default.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
@@ -37,4 +37,5 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@Documented
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.stubbed.discovery.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public @interface ConditionalOnStubbedDiscoveryEnabled {
|
||||
|
||||
}
|
||||
|
||||
@@ -24,30 +24,27 @@ import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Maps Ivy based ids to service Ids. You might want to name the service you're calling
|
||||
* in another way than artifact id. If that's the case then this class should be used
|
||||
* to change do the proper mapping.
|
||||
* Maps Ivy based ids to service Ids. You might want to name the service you're calling in
|
||||
* another way than artifact id. If that's the case then this class should be used to
|
||||
* change do the proper mapping.
|
||||
*
|
||||
* Just provide in your properties file for example:
|
||||
*
|
||||
* stubrunner.idsToServiceIds:
|
||||
* fraudDetectionServer: someNameThatShouldMapFraudDetectionServer
|
||||
* stubrunner.idsToServiceIds: fraudDetectionServer:
|
||||
* someNameThatShouldMapFraudDetectionServer
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ConfigurationProperties("stubrunner")
|
||||
public class StubMapperProperties {
|
||||
|
||||
/**
|
||||
* Mapping of Ivy notation based ids to serviceIds
|
||||
* inside your application
|
||||
* Mapping of Ivy notation based ids to serviceIds inside your application
|
||||
*
|
||||
* Example
|
||||
*
|
||||
* "a:b" -> "myService"
|
||||
* "artifactId" -> "myOtherService"
|
||||
* "a:b" -> "myService" "artifactId" -> "myOtherService"
|
||||
*/
|
||||
private Map<String, String> idsToServiceIds = new HashMap<>();
|
||||
|
||||
@@ -65,8 +62,8 @@ public class StubMapperProperties {
|
||||
if (StringUtils.hasText(id)) {
|
||||
return id;
|
||||
}
|
||||
String groupAndArtifact = this.idsToServiceIds.get(stubConfiguration.getGroupId() +
|
||||
":" + stubConfiguration.getArtifactId());
|
||||
String groupAndArtifact = this.idsToServiceIds.get(
|
||||
stubConfiguration.getGroupId() + ":" + stubConfiguration.getArtifactId());
|
||||
if (StringUtils.hasText(groupAndArtifact)) {
|
||||
return groupAndArtifact;
|
||||
}
|
||||
@@ -81,4 +78,5 @@ public class StubMapperProperties {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,27 +32,30 @@ import org.springframework.cloud.contract.stubrunner.StubFinder;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Custom version of {@link DiscoveryClient} that tries to find an instance
|
||||
* in one of the started WireMock servers
|
||||
* Custom version of {@link DiscoveryClient} that tries to find an instance in one of the
|
||||
* started WireMock servers
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
private static final Log log = LogFactory
|
||||
.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final DiscoveryClient delegate;
|
||||
|
||||
private final StubFinder stubFinder;
|
||||
|
||||
private final StubMapperProperties stubMapperProperties;
|
||||
|
||||
public StubRunnerDiscoveryClient(DiscoveryClient delegate, StubFinder stubFinder,
|
||||
StubMapperProperties stubMapperProperties, String springAppName) {
|
||||
this.delegate = delegate instanceof StubRunnerDiscoveryClient ?
|
||||
noOpDiscoveryClient() : delegate;
|
||||
this.delegate = delegate instanceof StubRunnerDiscoveryClient
|
||||
? noOpDiscoveryClient() : delegate;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will delegate calls to discovery service [" + this.delegate + "] if a stub is not found");
|
||||
log.debug("Will delegate calls to discovery service [" + this.delegate
|
||||
+ "] if a stub is not found");
|
||||
}
|
||||
this.stubFinder = stubFinder;
|
||||
this.stubMapperProperties = stubMapperProperties;
|
||||
@@ -62,7 +65,8 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
StubMapperProperties stubMapperProperties, String springAppName) {
|
||||
this.delegate = noOpDiscoveryClient();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will delegate calls to discovery service [" + this.delegate + "] if a stub is not found");
|
||||
log.debug("Will delegate calls to discovery service [" + this.delegate
|
||||
+ "] if a stub is not found");
|
||||
}
|
||||
this.stubFinder = stubFinder;
|
||||
this.stubMapperProperties = stubMapperProperties;
|
||||
@@ -76,7 +80,8 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
public String description() {
|
||||
try {
|
||||
return this.delegate.description();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to fetch description from delegate", e);
|
||||
}
|
||||
@@ -86,23 +91,25 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
@Override
|
||||
public List<ServiceInstance> getInstances(String serviceId) {
|
||||
String ivyNotation = this.stubMapperProperties.fromServiceIdToIvyNotation(serviceId);
|
||||
String ivyNotation = this.stubMapperProperties
|
||||
.fromServiceIdToIvyNotation(serviceId);
|
||||
String serviceToFind = StringUtils.hasText(ivyNotation) ? ivyNotation : serviceId;
|
||||
URL stubUrl = this.stubFinder.findStubUrl(serviceToFind);
|
||||
log.info("Resolved from ivy [" + ivyNotation + "] service to find [" + serviceToFind + "]. "
|
||||
+ "Found stub is available under URL [" + stubUrl + "]");
|
||||
log.info("Resolved from ivy [" + ivyNotation + "] service to find ["
|
||||
+ serviceToFind + "]. " + "Found stub is available under URL [" + stubUrl
|
||||
+ "]");
|
||||
if (stubUrl == null) {
|
||||
return getInstancesFromDelegate(serviceId);
|
||||
}
|
||||
return Collections.<ServiceInstance>singletonList(
|
||||
new StubRunnerServiceInstance(serviceId, stubUrl.getHost(), stubUrl.getPort(), toUri(stubUrl))
|
||||
);
|
||||
return Collections.<ServiceInstance>singletonList(new StubRunnerServiceInstance(
|
||||
serviceId, stubUrl.getHost(), stubUrl.getPort(), toUri(stubUrl)));
|
||||
}
|
||||
|
||||
private List<ServiceInstance> getInstancesFromDelegate(String serviceId) {
|
||||
try {
|
||||
return new ArrayList<>(this.delegate.getInstances(serviceId));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to fetch instances from delegate", e);
|
||||
}
|
||||
@@ -113,7 +120,8 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
private URI toUri(URL url) {
|
||||
try {
|
||||
return url.toURI();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +139,8 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
private List<String> getServicesFromDelegate() {
|
||||
try {
|
||||
return new ArrayList<>(this.delegate.getServices());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to fetch services from delegate", e);
|
||||
}
|
||||
@@ -143,6 +152,7 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
public int getOrder() {
|
||||
return this.delegate.getOrder();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class StubRunnerNoOpDiscoveryClient implements DiscoveryClient {
|
||||
@@ -161,4 +171,5 @@ class StubRunnerNoOpDiscoveryClient implements DiscoveryClient {
|
||||
public List<String> getServices() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,14 +26,16 @@ import org.springframework.cloud.client.ServiceInstance;
|
||||
* {@link ServiceInstance} with a helpful constructor
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class StubRunnerServiceInstance implements ServiceInstance {
|
||||
|
||||
private final String serviceId;
|
||||
|
||||
private final String host;
|
||||
|
||||
private final int port;
|
||||
|
||||
private final URI uri;
|
||||
|
||||
public StubRunnerServiceInstance(String serviceId, String host, int port, URI uri) {
|
||||
@@ -72,4 +74,5 @@ class StubRunnerServiceInstance implements ServiceInstance {
|
||||
public Map<String, String> getMetadata() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* Wraps {@link DiscoveryClient} in a Stub Runner implementation that tries to find
|
||||
* a corresponding WireMock server for a searched dependency
|
||||
* Wraps {@link DiscoveryClient} in a Stub Runner implementation that tries to find a
|
||||
* corresponding WireMock server for a searched dependency
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@@ -43,7 +43,8 @@ import org.springframework.core.env.Environment;
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.enabled", matchIfMissing = true)
|
||||
public class StubRunnerSpringCloudAutoConfiguration {
|
||||
|
||||
@Autowired BeanFactory beanFactory;
|
||||
@Autowired
|
||||
BeanFactory beanFactory;
|
||||
|
||||
@Bean
|
||||
public StubRunnerDiscoveryClientWrapper stubRunnerDiscoveryClientWrapper() {
|
||||
@@ -57,7 +58,8 @@ public class StubRunnerSpringCloudAutoConfiguration {
|
||||
public DiscoveryClient noOpStubRunnerDiscoveryClient(StubFinder stubFinder,
|
||||
StubMapperProperties stubMapperProperties,
|
||||
@Value("${spring.application.name:unknown}") String springAppName) {
|
||||
return new StubRunnerDiscoveryClient(stubFinder, stubMapperProperties, springAppName);
|
||||
return new StubRunnerDiscoveryClient(stubFinder, stubMapperProperties,
|
||||
springAppName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -65,33 +67,43 @@ public class StubRunnerSpringCloudAutoConfiguration {
|
||||
class StubRunnerDiscoveryClientWrapper implements BeanPostProcessor {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
DiscoveryClient discoveryClient;
|
||||
|
||||
StubFinder stubFinder;
|
||||
|
||||
StubMapperProperties stubMapperProperties;
|
||||
|
||||
String springAppName;
|
||||
|
||||
Boolean stubbedDiscoveryEnabled;
|
||||
|
||||
Boolean cloudDelegateEnabled;
|
||||
|
||||
StubRunnerDiscoveryClientWrapper(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof DiscoveryClient && !(bean instanceof StubRunnerDiscoveryClient)) {
|
||||
if (bean instanceof DiscoveryClient
|
||||
&& !(bean instanceof StubRunnerDiscoveryClient)) {
|
||||
if (!isStubbedDiscoveryEnabled()) {
|
||||
return bean;
|
||||
}
|
||||
if (isCloudDelegateEnabled()) {
|
||||
return new StubRunnerDiscoveryClient((DiscoveryClient) bean,
|
||||
stubFinder(), stubMapperProperties(), springAppName());
|
||||
return new StubRunnerDiscoveryClient((DiscoveryClient) bean, stubFinder(),
|
||||
stubMapperProperties(), springAppName());
|
||||
}
|
||||
return new StubRunnerDiscoveryClient(stubFinder(), stubMapperProperties(), springAppName());
|
||||
return new StubRunnerDiscoveryClient(stubFinder(), stubMapperProperties(),
|
||||
springAppName());
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
@@ -105,7 +117,8 @@ class StubRunnerDiscoveryClientWrapper implements BeanPostProcessor {
|
||||
|
||||
StubMapperProperties stubMapperProperties() {
|
||||
if (this.stubMapperProperties == null) {
|
||||
this.stubMapperProperties = this.beanFactory.getBean(StubMapperProperties.class);
|
||||
this.stubMapperProperties = this.beanFactory
|
||||
.getBean(StubMapperProperties.class);
|
||||
}
|
||||
return this.stubMapperProperties;
|
||||
}
|
||||
@@ -120,21 +133,20 @@ class StubRunnerDiscoveryClientWrapper implements BeanPostProcessor {
|
||||
|
||||
boolean isStubbedDiscoveryEnabled() {
|
||||
if (this.stubbedDiscoveryEnabled == null) {
|
||||
this.stubbedDiscoveryEnabled = Boolean.valueOf(
|
||||
this.beanFactory.getBean(Environment.class)
|
||||
.getProperty("stubrunner.cloud.stubbed.discovery.enabled", "true")
|
||||
);
|
||||
this.stubbedDiscoveryEnabled = Boolean
|
||||
.valueOf(this.beanFactory.getBean(Environment.class).getProperty(
|
||||
"stubrunner.cloud.stubbed.discovery.enabled", "true"));
|
||||
}
|
||||
return this.stubbedDiscoveryEnabled;
|
||||
}
|
||||
|
||||
boolean isCloudDelegateEnabled() {
|
||||
if (this.cloudDelegateEnabled == null) {
|
||||
this.cloudDelegateEnabled = Boolean.valueOf(
|
||||
this.beanFactory.getBean(Environment.class)
|
||||
.getProperty("stubrunner.cloud.delegate.enabled", "false")
|
||||
);
|
||||
this.cloudDelegateEnabled = Boolean
|
||||
.valueOf(this.beanFactory.getBean(Environment.class)
|
||||
.getProperty("stubrunner.cloud.delegate.enabled", "false"));
|
||||
}
|
||||
return this.cloudDelegateEnabled;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,9 +4,10 @@ package org.springframework.cloud.contract.stubrunner.spring.cloud;
|
||||
* Contract for registering stubs in a Service Discovery.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface StubsRegistrar extends AutoCloseable {
|
||||
|
||||
void registerStubs();
|
||||
|
||||
}
|
||||
@@ -20,24 +20,28 @@ import org.springframework.util.StringUtils;
|
||||
* Registers all stubs in Zookeeper Service Discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ConsulStubsRegistrar implements StubsRegistrar {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
private static final Log log = LogFactory
|
||||
.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final StubRunning stubRunning;
|
||||
|
||||
private final ConsulClient consulClient;
|
||||
|
||||
private final StubMapperProperties stubMapperProperties;
|
||||
|
||||
private final ConsulDiscoveryProperties consulDiscoveryProperties;
|
||||
|
||||
private final InetUtils inetUtils;
|
||||
|
||||
private final List<NewService> services = new LinkedList<>();
|
||||
|
||||
public ConsulStubsRegistrar(StubRunning stubRunning, ConsulClient consulClient,
|
||||
StubMapperProperties stubMapperProperties,
|
||||
ConsulDiscoveryProperties consulDiscoveryProperties,
|
||||
InetUtils inetUtils) {
|
||||
StubMapperProperties stubMapperProperties,
|
||||
ConsulDiscoveryProperties consulDiscoveryProperties, InetUtils inetUtils) {
|
||||
this.stubRunning = stubRunning;
|
||||
this.consulClient = consulClient;
|
||||
this.stubMapperProperties = stubMapperProperties;
|
||||
@@ -45,7 +49,8 @@ public class ConsulStubsRegistrar implements StubsRegistrar {
|
||||
this.inetUtils = inetUtils;
|
||||
}
|
||||
|
||||
@Override public void registerStubs() {
|
||||
@Override
|
||||
public void registerStubs() {
|
||||
Map<StubConfiguration, Integer> activeStubs = this.stubRunning.runStubs()
|
||||
.validNamesAndPorts();
|
||||
for (Map.Entry<StubConfiguration, Integer> entry : activeStubs.entrySet()) {
|
||||
@@ -54,12 +59,14 @@ public class ConsulStubsRegistrar implements StubsRegistrar {
|
||||
try {
|
||||
this.consulClient.agentServiceRegister(newService);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Successfully registered stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
log.debug("Successfully registered stub ["
|
||||
+ entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception occurred while trying to register a stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
log.warn("Exception occurred while trying to register a stub ["
|
||||
+ entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery", e);
|
||||
}
|
||||
}
|
||||
@@ -67,9 +74,10 @@ public class ConsulStubsRegistrar implements StubsRegistrar {
|
||||
|
||||
protected NewService newService(StubConfiguration stubConfiguration, Integer port) {
|
||||
NewService newService = new NewService();
|
||||
newService.setAddress(StringUtils.hasText(this.consulDiscoveryProperties.getHostname()) ?
|
||||
this.consulDiscoveryProperties.getHostname() :
|
||||
this.inetUtils.findFirstNonLoopbackAddress().getHostName());
|
||||
newService.setAddress(
|
||||
StringUtils.hasText(this.consulDiscoveryProperties.getHostname())
|
||||
? this.consulDiscoveryProperties.getHostname()
|
||||
: this.inetUtils.findFirstNonLoopbackAddress().getHostName());
|
||||
newService.setId(stubConfiguration.getArtifactId());
|
||||
newService.setName(name(stubConfiguration));
|
||||
newService.setPort(port);
|
||||
@@ -91,4 +99,5 @@ public class ConsulStubsRegistrar implements StubsRegistrar {
|
||||
this.consulClient.agentServiceDeregister(service.getId());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,19 +38,19 @@ import org.springframework.context.annotation.Configuration;
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter(value = {StubRunnerConfiguration.class,
|
||||
ConsulServiceRegistryAutoConfiguration.class})
|
||||
@AutoConfigureAfter(value = { StubRunnerConfiguration.class,
|
||||
ConsulServiceRegistryAutoConfiguration.class })
|
||||
@ConditionalOnClass(ConsulClient.class)
|
||||
@ConditionalOnStubbedDiscoveryDisabled
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.consul.enabled", matchIfMissing = true)
|
||||
public class StubRunnerSpringCloudConsulAutoConfiguration {
|
||||
|
||||
@Bean(initMethod = "registerStubs")
|
||||
public StubsRegistrar stubsRegistrar(StubRunning stubRunning, ConsulClient consulClient,
|
||||
StubMapperProperties stubMapperProperties,
|
||||
ConsulDiscoveryProperties consulDiscoveryProperties,
|
||||
InetUtils inetUtils) {
|
||||
public StubsRegistrar stubsRegistrar(StubRunning stubRunning,
|
||||
ConsulClient consulClient, StubMapperProperties stubMapperProperties,
|
||||
ConsulDiscoveryProperties consulDiscoveryProperties, InetUtils inetUtils) {
|
||||
return new ConsulStubsRegistrar(stubRunning, consulClient, stubMapperProperties,
|
||||
consulDiscoveryProperties, inetUtils);
|
||||
consulDiscoveryProperties, inetUtils);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,4 +36,5 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@Documented
|
||||
@ConditionalOnProperty(value = "eureka.client.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@interface ConditionalOnEurekaEnabled {
|
||||
|
||||
}
|
||||
|
||||
@@ -32,28 +32,34 @@ import com.netflix.discovery.EurekaClient;
|
||||
* Registers all stubs in Eureka Service Discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class EurekaStubsRegistrar implements StubsRegistrar {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
private static final Log log = LogFactory
|
||||
.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final StubRunning stubRunning;
|
||||
|
||||
private final StubMapperProperties stubMapperProperties;
|
||||
|
||||
private final InetUtils inetUtils;
|
||||
|
||||
private final EurekaInstanceConfigBean eurekaInstanceConfigBean;
|
||||
|
||||
private final EurekaClientConfigBean eurekaClientConfigBean;
|
||||
|
||||
private final List<EurekaRegistration> registrations = new LinkedList<>();
|
||||
|
||||
private final ServiceRegistry<EurekaRegistration> serviceRegistry;
|
||||
|
||||
private final ApplicationContext context;
|
||||
|
||||
public EurekaStubsRegistrar(StubRunning stubRunning,
|
||||
ServiceRegistry<EurekaRegistration> serviceRegistry,
|
||||
StubMapperProperties stubMapperProperties, InetUtils inetUtils,
|
||||
EurekaInstanceConfigBean eurekaInstanceConfigBean,
|
||||
EurekaClientConfigBean eurekaClientConfigBean,
|
||||
ApplicationContext context) {
|
||||
EurekaClientConfigBean eurekaClientConfigBean, ApplicationContext context) {
|
||||
this.stubRunning = stubRunning;
|
||||
this.stubMapperProperties = stubMapperProperties;
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
@@ -63,7 +69,8 @@ public class EurekaStubsRegistrar implements StubsRegistrar {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override public void registerStubs() {
|
||||
@Override
|
||||
public void registerStubs() {
|
||||
Map<StubConfiguration, Integer> activeStubs = this.stubRunning.runStubs()
|
||||
.validNamesAndPorts();
|
||||
for (Map.Entry<StubConfiguration, Integer> entry : activeStubs.entrySet()) {
|
||||
@@ -72,21 +79,23 @@ public class EurekaStubsRegistrar implements StubsRegistrar {
|
||||
+ instance.getHostname() + ", " + instance.getNonSecurePort() + ", "
|
||||
+ instance.getInstanceId() + "]");
|
||||
InstanceInfo instanceInfo = new InstanceInfoFactory().create(instance);
|
||||
ApplicationInfoManager applicationInfoManager = new ApplicationInfoManager(instance, instanceInfo);
|
||||
ApplicationInfoManager applicationInfoManager = new ApplicationInfoManager(
|
||||
instance, instanceInfo);
|
||||
AbstractDiscoveryClientOptionalArgs args = args();
|
||||
EurekaClient client = new CloudEurekaClient(applicationInfoManager, this.eurekaClientConfigBean, args, this.context);
|
||||
EurekaClient client = new CloudEurekaClient(applicationInfoManager,
|
||||
this.eurekaClientConfigBean, args, this.context);
|
||||
EurekaRegistration registration = EurekaRegistration.builder(instance)
|
||||
.with(this.eurekaClientConfigBean, this.context)
|
||||
.with(client)
|
||||
.build();
|
||||
.with(this.eurekaClientConfigBean, this.context).with(client).build();
|
||||
this.registrations.add(registration);
|
||||
try {
|
||||
this.serviceRegistry.register(registration);
|
||||
log.info("Successfully registered stub " + "[" + entry.getKey()
|
||||
.toColonSeparatedDependencyNotation() + "] in Service Discovery");
|
||||
log.info("Successfully registered stub " + "["
|
||||
+ entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery");
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception occurred while trying to register a stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
log.warn("Exception occurred while trying to register a stub ["
|
||||
+ entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery", e);
|
||||
}
|
||||
}
|
||||
@@ -94,27 +103,29 @@ public class EurekaStubsRegistrar implements StubsRegistrar {
|
||||
|
||||
private AbstractDiscoveryClientOptionalArgs args() {
|
||||
try {
|
||||
return this.context
|
||||
.getBean(AbstractDiscoveryClientOptionalArgs.class);
|
||||
} catch (BeansException e) {
|
||||
return this.context.getBean(AbstractDiscoveryClientOptionalArgs.class);
|
||||
}
|
||||
catch (BeansException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private EurekaInstanceConfigBean registration(Map.Entry<StubConfiguration, Integer> entry) {
|
||||
private EurekaInstanceConfigBean registration(
|
||||
Map.Entry<StubConfiguration, Integer> entry) {
|
||||
EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(this.inetUtils);
|
||||
String appName = name(entry.getKey());
|
||||
config.setInstanceEnabledOnit(true);
|
||||
InetAddress address = this.inetUtils.findFirstNonLoopbackAddress();
|
||||
config.setIpAddress(address.getHostAddress());
|
||||
config.setHostname(StringUtils.hasText(hostName(entry)) ?
|
||||
hostName(entry) : address.getHostName());
|
||||
config.setHostname(StringUtils.hasText(hostName(entry)) ? hostName(entry)
|
||||
: address.getHostName());
|
||||
config.setAppname(appName);
|
||||
config.setVirtualHostName(appName);
|
||||
config.setSecureVirtualHostName(appName);
|
||||
int port = port(entry);
|
||||
config.setNonSecurePort(port);
|
||||
config.setInstanceId(address.getHostAddress() + ":" + entry.getKey().getArtifactId() + ":" + port);
|
||||
config.setInstanceId(address.getHostAddress() + ":"
|
||||
+ entry.getKey().getArtifactId() + ":" + port);
|
||||
config.setLeaseRenewalIntervalInSeconds(1);
|
||||
return config;
|
||||
}
|
||||
@@ -142,4 +153,5 @@ public class EurekaStubsRegistrar implements StubsRegistrar {
|
||||
this.serviceRegistry.deregister(registration);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -47,11 +47,11 @@ import org.springframework.core.env.Environment;
|
||||
* Autoconfiguration for registering stubs in a Eureka Service discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter({StubRunnerConfiguration.class, EurekaClientAutoConfiguration.class})
|
||||
@AutoConfigureAfter({ StubRunnerConfiguration.class,
|
||||
EurekaClientAutoConfiguration.class })
|
||||
@ConditionalOnClass(CloudEurekaClient.class)
|
||||
@ConditionalOnStubbedDiscoveryDisabled
|
||||
@ConditionalOnEurekaEnabled
|
||||
@@ -61,43 +61,58 @@ public class StubRunnerSpringCloudEurekaAutoConfiguration {
|
||||
@Profile("!cloud")
|
||||
@Configuration
|
||||
protected static class NonCloudConfig {
|
||||
|
||||
@Bean(initMethod = "registerStubs")
|
||||
public StubsRegistrar stubsRegistrar(StubRunning stubRunning,
|
||||
ServiceRegistry<EurekaRegistration> serviceRegistry, ApplicationContext context,
|
||||
StubMapperProperties stubMapperProperties, InetUtils inetUtils,
|
||||
EurekaInstanceConfigBean eurekaInstanceConfigBean, EurekaClientConfigBean eurekaClientConfigBean) {
|
||||
return new EurekaStubsRegistrar(stubRunning, serviceRegistry, stubMapperProperties, inetUtils,
|
||||
eurekaInstanceConfigBean, eurekaClientConfigBean, context);
|
||||
ServiceRegistry<EurekaRegistration> serviceRegistry,
|
||||
ApplicationContext context, StubMapperProperties stubMapperProperties,
|
||||
InetUtils inetUtils, EurekaInstanceConfigBean eurekaInstanceConfigBean,
|
||||
EurekaClientConfigBean eurekaClientConfigBean) {
|
||||
return new EurekaStubsRegistrar(stubRunning, serviceRegistry,
|
||||
stubMapperProperties, inetUtils, eurekaInstanceConfigBean,
|
||||
eurekaClientConfigBean, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Profile("cloud")
|
||||
@Configuration
|
||||
protected static class CloudConfig {
|
||||
|
||||
private static final int DEFAULT_PORT = 80;
|
||||
|
||||
private static final Log log = LogFactory.getLog(CloudConfig.class);
|
||||
|
||||
@Autowired Environment environment;
|
||||
@Autowired
|
||||
Environment environment;
|
||||
|
||||
@Bean(initMethod = "registerStubs")
|
||||
public StubsRegistrar stubsRegistrar(StubRunning stubRunning,
|
||||
ServiceRegistry<EurekaRegistration> serviceRegistry, ApplicationContext context,
|
||||
StubMapperProperties stubMapperProperties, InetUtils inetUtils,
|
||||
EurekaInstanceConfigBean eurekaInstanceConfigBean, EurekaClientConfigBean eurekaClientConfigBean) {
|
||||
return new EurekaStubsRegistrar(stubRunning, serviceRegistry, stubMapperProperties, inetUtils,
|
||||
eurekaInstanceConfigBean, eurekaClientConfigBean, context) {
|
||||
@Override protected String hostName(Map.Entry<StubConfiguration, Integer> entry) {
|
||||
String hostname =
|
||||
CloudConfig.this.environment.getProperty("application.hostname") +
|
||||
"-" + entry.getValue() + "." + CloudConfig.this.environment.getProperty("application.domain");
|
||||
log.info("Registering stub [" + entry.getKey().getArtifactId() + "] with hostname [" + hostname + "]");
|
||||
ServiceRegistry<EurekaRegistration> serviceRegistry,
|
||||
ApplicationContext context, StubMapperProperties stubMapperProperties,
|
||||
InetUtils inetUtils, EurekaInstanceConfigBean eurekaInstanceConfigBean,
|
||||
EurekaClientConfigBean eurekaClientConfigBean) {
|
||||
return new EurekaStubsRegistrar(stubRunning, serviceRegistry,
|
||||
stubMapperProperties, inetUtils, eurekaInstanceConfigBean,
|
||||
eurekaClientConfigBean, context) {
|
||||
@Override
|
||||
protected String hostName(Map.Entry<StubConfiguration, Integer> entry) {
|
||||
String hostname = CloudConfig.this.environment
|
||||
.getProperty("application.hostname") + "-" + entry.getValue()
|
||||
+ "." + CloudConfig.this.environment
|
||||
.getProperty("application.domain");
|
||||
log.info("Registering stub [" + entry.getKey().getArtifactId()
|
||||
+ "] with hostname [" + hostname + "]");
|
||||
return hostname;
|
||||
}
|
||||
|
||||
@Override protected int port(Map.Entry<StubConfiguration, Integer> entry) {
|
||||
@Override
|
||||
protected int port(Map.Entry<StubConfiguration, Integer> entry) {
|
||||
return DEFAULT_PORT;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,18 +26,20 @@ import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
|
||||
/**
|
||||
* Ribbon AutoConfiguration that manipulates the service id to make the service
|
||||
* be picked from the list of available WireMock instance if one is available.
|
||||
* Ribbon AutoConfiguration that manipulates the service id to make the service be picked
|
||||
* from the list of available WireMock instance if one is available.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class StubRunnerRibbonBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private StubFinder stubFinder;
|
||||
|
||||
private StubMapperProperties stubMapperProperties;
|
||||
|
||||
private IClientConfig clientConfig;
|
||||
|
||||
StubRunnerRibbonBeanPostProcessor(BeanFactory beanFactory) {
|
||||
@@ -53,7 +55,8 @@ class StubRunnerRibbonBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private StubMapperProperties stubMapperProperties() {
|
||||
if (this.stubMapperProperties == null) {
|
||||
this.stubMapperProperties = this.beanFactory.getBean(StubMapperProperties.class);
|
||||
this.stubMapperProperties = this.beanFactory
|
||||
.getBean(StubMapperProperties.class);
|
||||
}
|
||||
return this.stubMapperProperties;
|
||||
}
|
||||
@@ -66,15 +69,19 @@ class StubRunnerRibbonBeanPostProcessor implements BeanPostProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof ServerList && !(bean instanceof StubRunnerRibbonServerList)) {
|
||||
return new StubRunnerRibbonServerList(stubFinder(), stubMapperProperties(), clientConfig());
|
||||
return new StubRunnerRibbonServerList(stubFinder(), stubMapperProperties(),
|
||||
clientConfig());
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,8 +32,10 @@ import org.springframework.context.annotation.Role;
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
class StubRunnerRibbonConfiguration {
|
||||
|
||||
@Bean
|
||||
static StubRunnerRibbonBeanPostProcessor stubRunnerRibbonBeanPostProcessor(BeanFactory beanFactory) {
|
||||
static StubRunnerRibbonBeanPostProcessor stubRunnerRibbonBeanPostProcessor(
|
||||
BeanFactory beanFactory) {
|
||||
return new StubRunnerRibbonBeanPostProcessor(beanFactory);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,12 +36,12 @@ import org.springframework.util.StringUtils;
|
||||
* Stub Runner representation of a server list
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class StubRunnerRibbonServerList implements ServerList<Server> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
private static final Log log = LogFactory
|
||||
.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final ServerList<Server> serverList;
|
||||
|
||||
@@ -50,10 +50,12 @@ class StubRunnerRibbonServerList implements ServerList<Server> {
|
||||
final IClientConfig clientConfig) {
|
||||
String serviceName = clientConfig.getClientName();
|
||||
String mappedServiceName = StringUtils
|
||||
.hasText(stubMapperProperties.fromServiceIdToIvyNotation(serviceName)) ?
|
||||
stubMapperProperties.fromServiceIdToIvyNotation(serviceName) : serviceName;
|
||||
.hasText(stubMapperProperties.fromServiceIdToIvyNotation(serviceName))
|
||||
? stubMapperProperties.fromServiceIdToIvyNotation(serviceName)
|
||||
: serviceName;
|
||||
RunningStubs runningStubs = stubFinder.findAllRunningStubs();
|
||||
final Map.Entry<StubConfiguration, Integer> entry = runningStubs.getEntry(mappedServiceName);
|
||||
final Map.Entry<StubConfiguration, Integer> entry = runningStubs
|
||||
.getEntry(mappedServiceName);
|
||||
final List<Server> servers = new ArrayList<>();
|
||||
if (entry != null) {
|
||||
servers.add(new Server("localhost", entry.getValue()) {
|
||||
@@ -62,7 +64,8 @@ class StubRunnerRibbonServerList implements ServerList<Server> {
|
||||
return new MetaInfo() {
|
||||
@Override
|
||||
public String getAppName() {
|
||||
return stubMapperProperties.fromIvyNotationToId(entry.getKey().toColonSeparatedDependencyNotation());
|
||||
return stubMapperProperties.fromIvyNotationToId(
|
||||
entry.getKey().toColonSeparatedDependencyNotation());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,12 +75,14 @@ class StubRunnerRibbonServerList implements ServerList<Server> {
|
||||
|
||||
@Override
|
||||
public String getServiceIdForDiscovery() {
|
||||
return stubMapperProperties.fromIvyNotationToId(entry.getKey().getArtifactId());
|
||||
return stubMapperProperties
|
||||
.fromIvyNotationToId(entry.getKey().getArtifactId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInstanceId() {
|
||||
return stubMapperProperties.fromIvyNotationToId(entry.getKey().getArtifactId());
|
||||
return stubMapperProperties
|
||||
.fromIvyNotationToId(entry.getKey().getArtifactId());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -105,4 +110,5 @@ class StubRunnerRibbonServerList implements ServerList<Server> {
|
||||
public List<Server> getUpdatedListOfServers() {
|
||||
return this.serverList.getUpdatedListOfServers();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ import org.springframework.context.annotation.Configuration;
|
||||
* Autoconfiguration for registering stubs in a Zookeeper Service discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter({ StubRunnerConfiguration.class, CuratorServiceDiscoveryAutoConfiguration.class })
|
||||
@AutoConfigureAfter({ StubRunnerConfiguration.class,
|
||||
CuratorServiceDiscoveryAutoConfiguration.class })
|
||||
@ConditionalOnClass(org.apache.curator.x.discovery.ServiceInstance.class)
|
||||
@ConditionalOnStubbedDiscoveryDisabled
|
||||
@ConditionalOnZookeeperDiscoveryEnabled
|
||||
@@ -47,8 +47,11 @@ import org.springframework.context.annotation.Configuration;
|
||||
public class StubRunnerSpringCloudZookeeperAutoConfiguration {
|
||||
|
||||
@Bean(initMethod = "registerStubs")
|
||||
public StubsRegistrar stubsRegistrar(StubRunning stubRunning, CuratorFramework curatorFramework,
|
||||
StubMapperProperties stubMapperProperties, ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
|
||||
return new ZookeeperStubsRegistrar(stubRunning, curatorFramework, stubMapperProperties, zookeeperDiscoveryProperties);
|
||||
public StubsRegistrar stubsRegistrar(StubRunning stubRunning,
|
||||
CuratorFramework curatorFramework, StubMapperProperties stubMapperProperties,
|
||||
ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
|
||||
return new ZookeeperStubsRegistrar(stubRunning, curatorFramework,
|
||||
stubMapperProperties, zookeeperDiscoveryProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,21 +23,25 @@ import org.springframework.util.StringUtils;
|
||||
* Registers all stubs in Zookeeper Service Discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ZookeeperStubsRegistrar implements StubsRegistrar {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
private static final Log log = LogFactory
|
||||
.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final StubRunning stubRunning;
|
||||
|
||||
private final CuratorFramework curatorFramework;
|
||||
|
||||
private final StubMapperProperties stubMapperProperties;
|
||||
|
||||
private final ZookeeperDiscoveryProperties zookeeperDiscoveryProperties;
|
||||
|
||||
private final List<ServiceDiscovery> discoveryList = new LinkedList<>();
|
||||
|
||||
public ZookeeperStubsRegistrar(StubRunning stubRunning, CuratorFramework curatorFramework,
|
||||
StubMapperProperties stubMapperProperties,
|
||||
public ZookeeperStubsRegistrar(StubRunning stubRunning,
|
||||
CuratorFramework curatorFramework, StubMapperProperties stubMapperProperties,
|
||||
ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
|
||||
this.stubRunning = stubRunning;
|
||||
this.curatorFramework = curatorFramework;
|
||||
@@ -45,30 +49,36 @@ public class ZookeeperStubsRegistrar implements StubsRegistrar {
|
||||
this.zookeeperDiscoveryProperties = zookeeperDiscoveryProperties;
|
||||
}
|
||||
|
||||
@Override public void registerStubs() {
|
||||
@Override
|
||||
public void registerStubs() {
|
||||
Map<StubConfiguration, Integer> activeStubs = this.stubRunning.runStubs()
|
||||
.validNamesAndPorts();
|
||||
for (Map.Entry<StubConfiguration, Integer> entry : activeStubs.entrySet()) {
|
||||
ServiceInstance serviceInstance = serviceInstance(entry.getKey(), entry.getValue());
|
||||
ServiceInstance serviceInstance = serviceInstance(entry.getKey(),
|
||||
entry.getValue());
|
||||
ServiceDiscovery serviceDiscovery = serviceDiscovery(serviceInstance);
|
||||
this.discoveryList.add(serviceDiscovery);
|
||||
try {
|
||||
serviceDiscovery.start();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Successfully registered stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
log.debug("Successfully registered stub ["
|
||||
+ entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception occurred while trying to register a stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
log.warn("Exception occurred while trying to register a stub ["
|
||||
+ entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected ServiceInstance serviceInstance(StubConfiguration stubConfiguration, int port) {
|
||||
protected ServiceInstance serviceInstance(StubConfiguration stubConfiguration,
|
||||
int port) {
|
||||
try {
|
||||
return ServiceInstance.builder().uriSpec(new UriSpec(this.zookeeperDiscoveryProperties.getUriSpec()))
|
||||
return ServiceInstance.builder()
|
||||
.uriSpec(new UriSpec(this.zookeeperDiscoveryProperties.getUriSpec()))
|
||||
.address("localhost").port(port).name(name(stubConfiguration))
|
||||
.build();
|
||||
}
|
||||
@@ -98,4 +108,5 @@ public class ZookeeperStubsRegistrar implements StubsRegistrar {
|
||||
discovery.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ import org.springframework.util.StringUtils;
|
||||
public class StubsParser {
|
||||
|
||||
/**
|
||||
* The string is expected to be a map with entry called "stubs"
|
||||
* that contains a list of Strings in the format
|
||||
* The string is expected to be a map with entry called "stubs" that contains a list
|
||||
* of Strings in the format
|
||||
*
|
||||
* <ul>
|
||||
* <li>groupid:artifactid:version:classifier:port</li>
|
||||
@@ -47,7 +47,8 @@ public class StubsParser {
|
||||
*
|
||||
* "a:b,c:d:e"
|
||||
*/
|
||||
public static List<StubConfiguration> fromString(Collection<String> collection, String defaultClassifier) {
|
||||
public static List<StubConfiguration> fromString(Collection<String> collection,
|
||||
String defaultClassifier) {
|
||||
List<StubConfiguration> stubs = new ArrayList<>();
|
||||
for (String config : collection) {
|
||||
if (StringUtils.hasText(config)) {
|
||||
@@ -58,7 +59,8 @@ public class StubsParser {
|
||||
}
|
||||
|
||||
public static Map<StubConfiguration, Integer> fromStringWithPort(String notation) {
|
||||
StubSpecification stub = StubSpecification.parse(notation, StubConfiguration.DEFAULT_CLASSIFIER);
|
||||
StubSpecification stub = StubSpecification.parse(notation,
|
||||
StubConfiguration.DEFAULT_CLASSIFIER);
|
||||
if (!stub.hasPort()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
@@ -66,7 +68,8 @@ public class StubsParser {
|
||||
}
|
||||
|
||||
public static String ivyFromStringWithPort(String notation) {
|
||||
StubSpecification stub = StubSpecification.parse(notation, StubConfiguration.DEFAULT_CLASSIFIER);
|
||||
StubSpecification stub = StubSpecification.parse(notation,
|
||||
StubConfiguration.DEFAULT_CLASSIFIER);
|
||||
if (!stub.hasPort()) {
|
||||
return "";
|
||||
}
|
||||
@@ -76,16 +79,18 @@ public class StubsParser {
|
||||
public static boolean hasPort(String id) {
|
||||
String[] splitEntry = id.split(":");
|
||||
try {
|
||||
Integer.valueOf(splitEntry[splitEntry.length-1]);
|
||||
Integer.valueOf(splitEntry[splitEntry.length - 1]);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StubSpecification {
|
||||
|
||||
private final StubConfiguration stub;
|
||||
|
||||
private final Integer port;
|
||||
|
||||
public StubSpecification(StubConfiguration stub, Integer port) {
|
||||
@@ -96,16 +101,20 @@ public class StubsParser {
|
||||
public boolean hasPort() {
|
||||
return this.port != null;
|
||||
}
|
||||
|
||||
|
||||
private static StubSpecification parse(String id, String defaultClassifier) {
|
||||
String[] splitEntry = id.split(":");
|
||||
Integer port = null;
|
||||
try {
|
||||
port = Integer.valueOf(splitEntry[splitEntry.length-1]);
|
||||
port = Integer.valueOf(splitEntry[splitEntry.length - 1]);
|
||||
id = id.substring(0, id.lastIndexOf(":"));
|
||||
} catch (NumberFormatException e) {}
|
||||
return new StubSpecification(new StubConfiguration(id, defaultClassifier), port);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
}
|
||||
return new StubSpecification(new StubConfiguration(id, defaultClassifier),
|
||||
port);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,7 +43,6 @@ public class ZipCategory {
|
||||
/**
|
||||
* Unzips this file. If the <tt>destination</tt> directory is not provided, it will
|
||||
* fall back to this file's parent directory.
|
||||
*
|
||||
* @param self
|
||||
* @param destination (optional), the destination directory where this file's content
|
||||
* will be unzipped to.
|
||||
@@ -58,8 +57,8 @@ public class ZipCategory {
|
||||
List<File> unzippedFiles = new ArrayList<>();
|
||||
try (InputStream fileInputStream = Files.newInputStream(self.toPath())) {
|
||||
try (ZipInputStream zipInput = new ZipInputStream(fileInputStream)) {
|
||||
for (ZipEntry entry = zipInput.getNextEntry(); entry != null; entry = zipInput
|
||||
.getNextEntry()) {
|
||||
for (ZipEntry entry = zipInput
|
||||
.getNextEntry(); entry != null; entry = zipInput.getNextEntry()) {
|
||||
if (!entry.isDirectory()) {
|
||||
final File file = new File(destination, entry.getName());
|
||||
if (file.getParentFile() != null) {
|
||||
@@ -77,7 +76,8 @@ public class ZipCategory {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException("Cannot unzip archive", e);
|
||||
}
|
||||
return unzippedFiles;
|
||||
@@ -87,4 +87,5 @@ public class ZipCategory {
|
||||
if (file != null && !file.isDirectory())
|
||||
throw new IllegalArgumentException("'destination' has to be a directory.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ import org.junit.rules.TemporaryFolder;
|
||||
*/
|
||||
public abstract class AbstractGitTest {
|
||||
|
||||
@Rule public TemporaryFolder tmp = new TemporaryFolder();
|
||||
@Rule
|
||||
public TemporaryFolder tmp = new TemporaryFolder();
|
||||
|
||||
File tmpFolder;
|
||||
|
||||
@Before
|
||||
@@ -53,7 +55,7 @@ public abstract class AbstractGitTest {
|
||||
try (PrintStream out = new PrintStream(new FileOutputStream(newFile))) {
|
||||
out.print("foo");
|
||||
}
|
||||
try(Git git = openGitProject(project)) {
|
||||
try (Git git = openGitProject(project)) {
|
||||
git.add().addFilepattern("newFile").call();
|
||||
}
|
||||
return newFile;
|
||||
@@ -61,7 +63,7 @@ public abstract class AbstractGitTest {
|
||||
|
||||
void setOriginOnProjectToTmp(File origin, File project, boolean push)
|
||||
throws GitAPIException, IOException, URISyntaxException {
|
||||
try(Git git = openGitProject(project)) {
|
||||
try (Git git = openGitProject(project)) {
|
||||
RemoteRemoveCommand remove = git.remoteRemove();
|
||||
remove.setName("origin");
|
||||
remove.call();
|
||||
@@ -72,7 +74,8 @@ public abstract class AbstractGitTest {
|
||||
command.call();
|
||||
StoredConfig config = git.getRepository().getConfig();
|
||||
RemoteConfig originConfig = new RemoteConfig(config, "origin");
|
||||
originConfig.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
|
||||
originConfig
|
||||
.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
|
||||
originConfig.update(config);
|
||||
config.save();
|
||||
}
|
||||
@@ -87,4 +90,5 @@ public abstract class AbstractGitTest {
|
||||
projectRepo.cloneProject(projectToClone.toURI());
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,10 +10,13 @@ import static org.assertj.core.api.BDDAssertions.then;
|
||||
*/
|
||||
public class ClasspathStubProviderTest {
|
||||
|
||||
@Test public void should_return_null_if_stub_mode_is_not_classpath() {
|
||||
StubDownloader stubDownloader = new ClasspathStubProvider().build(new StubRunnerOptionsBuilder().withStubsMode(
|
||||
StubRunnerProperties.StubsMode.REMOTE).build());
|
||||
@Test
|
||||
public void should_return_null_if_stub_mode_is_not_classpath() {
|
||||
StubDownloader stubDownloader = new ClasspathStubProvider()
|
||||
.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE).build());
|
||||
|
||||
then(stubDownloader).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,11 +14,14 @@ import org.junit.Test;
|
||||
*/
|
||||
public class CompositeStubDownloaderBuilderTests {
|
||||
|
||||
@Test public void should_delegate_work_to_other_stub_downloaders() {
|
||||
@Test
|
||||
public void should_delegate_work_to_other_stub_downloaders() {
|
||||
EmptyStubDownloaderBuilder emptyStubDownloaderBuilder = new EmptyStubDownloaderBuilder();
|
||||
ImpossibleToBuildStubDownloaderBuilder impossible = new ImpossibleToBuildStubDownloaderBuilder();
|
||||
List<StubDownloaderBuilder> builders = Arrays.asList(emptyStubDownloaderBuilder, impossible, new SomeStubDownloaderBuilder());
|
||||
CompositeStubDownloaderBuilder builder = new CompositeStubDownloaderBuilder(builders);
|
||||
List<StubDownloaderBuilder> builders = Arrays.asList(emptyStubDownloaderBuilder,
|
||||
impossible, new SomeStubDownloaderBuilder());
|
||||
CompositeStubDownloaderBuilder builder = new CompositeStubDownloaderBuilder(
|
||||
builders);
|
||||
StubDownloader downloader = builder.build(new StubRunnerOptionsBuilder().build());
|
||||
|
||||
Map.Entry<StubConfiguration, File> entry = downloader
|
||||
@@ -29,20 +32,23 @@ public class CompositeStubDownloaderBuilderTests {
|
||||
BDDAssertions.then(impossible.called).isTrue();
|
||||
}
|
||||
|
||||
@Test public void should_return_null_if_no_builders_were_passed() {
|
||||
@Test
|
||||
public void should_return_null_if_no_builders_were_passed() {
|
||||
CompositeStubDownloaderBuilder builder = new CompositeStubDownloaderBuilder(null);
|
||||
|
||||
StubDownloader downloader = builder.build(new StubRunnerOptionsBuilder().build());
|
||||
|
||||
BDDAssertions.then(downloader).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EmptyStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
|
||||
EmptyStubDownloader emptyStubDownloader;
|
||||
|
||||
@Override public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
@Override
|
||||
public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
this.emptyStubDownloader = new EmptyStubDownloader();
|
||||
return this.emptyStubDownloader;
|
||||
}
|
||||
@@ -50,13 +56,15 @@ class EmptyStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
boolean downloaderCalled() {
|
||||
return this.emptyStubDownloader.called;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ImpossibleToBuildStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
|
||||
boolean called;
|
||||
|
||||
@Override public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
@Override
|
||||
public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
this.called = true;
|
||||
return null;
|
||||
}
|
||||
@@ -64,25 +72,33 @@ class ImpossibleToBuildStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
}
|
||||
|
||||
class EmptyStubDownloader implements StubDownloader {
|
||||
|
||||
boolean called;
|
||||
|
||||
@Override public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
@Override
|
||||
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
StubConfiguration stubConfiguration) {
|
||||
this.called = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SomeStubDownloaderBuilder implements StubDownloaderBuilder {
|
||||
|
||||
@Override public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
@Override
|
||||
public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
|
||||
return new SomeStubDownloader();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SomeStubDownloader implements StubDownloader {
|
||||
@Override public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
|
||||
@Override
|
||||
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
|
||||
StubConfiguration stubConfiguration) {
|
||||
return new AbstractMap.SimpleEntry<>(stubConfiguration, new File("."));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,18 +36,25 @@ import static org.assertj.core.api.BDDAssertions.then;
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public class ContractProjectUpdaterTest extends AbstractGitTest {
|
||||
|
||||
File originalProject;
|
||||
|
||||
File project;
|
||||
|
||||
ContractProjectUpdater updater;
|
||||
|
||||
GitRepo gitRepo;
|
||||
|
||||
File origin;
|
||||
|
||||
@Rule public OutputCapture outputCapture = new OutputCapture();
|
||||
@Rule
|
||||
public OutputCapture outputCapture = new OutputCapture();
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
GitContractsRepo.CACHED_LOCATIONS.clear();
|
||||
this.originalProject = new File(GitRepoTests.class.getResource("/git_samples/contract-git").toURI());
|
||||
this.originalProject = new File(
|
||||
GitRepoTests.class.getResource("/git_samples/contract-git").toURI());
|
||||
TestUtils.prepareLocalRepo();
|
||||
this.gitRepo = new GitRepo(this.tmpFolder);
|
||||
this.origin = clonedProject(this.tmp.newFolder(), this.originalProject);
|
||||
@@ -56,31 +63,36 @@ public class ContractProjectUpdaterTest extends AbstractGitTest {
|
||||
setOriginOnProjectToTmp(this.origin, this.project, true);
|
||||
StubRunnerOptions options = new StubRunnerOptionsBuilder()
|
||||
.withStubRepositoryRoot("file://" + this.project.getAbsolutePath() + "/")
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.build();
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE).build();
|
||||
this.updater = new ContractProjectUpdater(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_push_changes_to_current_branch() throws Exception {
|
||||
File stubs = new File(GitRepoTests.class.getResource("/git_samples/sample_stubs").toURI());
|
||||
File stubs = new File(
|
||||
GitRepoTests.class.getResource("/git_samples/sample_stubs").toURI());
|
||||
|
||||
this.updater.updateContractProject("hello-world", stubs.toPath());
|
||||
|
||||
// project, not origin, cause we're making one more clone of the local copy
|
||||
try(Git git = openGitProject(this.project)) {
|
||||
try (Git git = openGitProject(this.project)) {
|
||||
RevCommit revCommit = git.log().call().iterator().next();
|
||||
then(revCommit.getShortMessage()).isEqualTo("Updating project [hello-world] with stubs");
|
||||
then(revCommit.getShortMessage())
|
||||
.isEqualTo("Updating project [hello-world] with stubs");
|
||||
// I have no idea but the file gets deleted after pushing
|
||||
git.reset().setMode(ResetCommand.ResetType.HARD).call();
|
||||
}
|
||||
BDDAssertions.then(new File(this.project, "META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json")).exists();
|
||||
BDDAssertions.then(new File(this.project,
|
||||
"META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json"))
|
||||
.exists();
|
||||
BDDAssertions.then(gitRepo.gitFactory.provider).isNull();
|
||||
BDDAssertions.then(outputCapture.toString()).contains("No custom credentials provider will be set");
|
||||
BDDAssertions.then(outputCapture.toString())
|
||||
.contains("No custom credentials provider will be set");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_push_changes_to_current_branch_using_credentials() throws Exception {
|
||||
public void should_push_changes_to_current_branch_using_credentials()
|
||||
throws Exception {
|
||||
StubRunnerOptions options = new StubRunnerOptionsBuilder()
|
||||
.withStubRepositoryRoot("file://" + this.project.getAbsolutePath() + "/")
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
@@ -89,56 +101,68 @@ public class ContractProjectUpdaterTest extends AbstractGitTest {
|
||||
put("git.username", "foo");
|
||||
put("git.password", "bar");
|
||||
}
|
||||
} )
|
||||
.build();
|
||||
}).build();
|
||||
ContractProjectUpdater updater = new ContractProjectUpdater(options);
|
||||
File stubs = new File(GitRepoTests.class.getResource("/git_samples/sample_stubs").toURI());
|
||||
File stubs = new File(
|
||||
GitRepoTests.class.getResource("/git_samples/sample_stubs").toURI());
|
||||
|
||||
updater.updateContractProject("hello-world", stubs.toPath());
|
||||
|
||||
// project, not origin, cause we're making one more clone of the local copy
|
||||
try(Git git = openGitProject(this.project)) {
|
||||
try (Git git = openGitProject(this.project)) {
|
||||
RevCommit revCommit = git.log().call().iterator().next();
|
||||
then(revCommit.getShortMessage()).isEqualTo("Updating project [hello-world] with stubs");
|
||||
then(revCommit.getShortMessage())
|
||||
.isEqualTo("Updating project [hello-world] with stubs");
|
||||
// I have no idea but the file gets deleted after pushing
|
||||
git.reset().setMode(ResetCommand.ResetType.HARD).call();
|
||||
}
|
||||
BDDAssertions.then(new File(this.project, "META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json")).exists();
|
||||
BDDAssertions.then(outputCapture.toString()).contains("Passed username and password - will set a custom credentials provider");
|
||||
BDDAssertions.then(new File(this.project,
|
||||
"META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json"))
|
||||
.exists();
|
||||
BDDAssertions.then(outputCapture.toString()).contains(
|
||||
"Passed username and password - will set a custom credentials provider");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_push_changes_to_current_branch_using_root_credentials() throws Exception {
|
||||
public void should_push_changes_to_current_branch_using_root_credentials()
|
||||
throws Exception {
|
||||
StubRunnerOptions options = new StubRunnerOptionsBuilder()
|
||||
.withStubRepositoryRoot("file://" + this.project.getAbsolutePath() + "/")
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withUsername("foo")
|
||||
.withPassword("bar")
|
||||
.build();
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE).withUsername("foo")
|
||||
.withPassword("bar").build();
|
||||
ContractProjectUpdater updater = new ContractProjectUpdater(options);
|
||||
File stubs = new File(GitRepoTests.class.getResource("/git_samples/sample_stubs").toURI());
|
||||
File stubs = new File(
|
||||
GitRepoTests.class.getResource("/git_samples/sample_stubs").toURI());
|
||||
|
||||
updater.updateContractProject("hello-world", stubs.toPath());
|
||||
|
||||
// project, not origin, cause we're making one more clone of the local copy
|
||||
try(Git git = openGitProject(this.project)) {
|
||||
try (Git git = openGitProject(this.project)) {
|
||||
RevCommit revCommit = git.log().call().iterator().next();
|
||||
then(revCommit.getShortMessage()).isEqualTo("Updating project [hello-world] with stubs");
|
||||
then(revCommit.getShortMessage())
|
||||
.isEqualTo("Updating project [hello-world] with stubs");
|
||||
// I have no idea but the file gets deleted after pushing
|
||||
git.reset().setMode(ResetCommand.ResetType.HARD).call();
|
||||
}
|
||||
BDDAssertions.then(new File(this.project, "META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json")).exists();
|
||||
BDDAssertions.then(outputCapture.toString()).contains("Passed username and password - will set a custom credentials provider");
|
||||
BDDAssertions.then(new File(this.project,
|
||||
"META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json"))
|
||||
.exists();
|
||||
BDDAssertions.then(outputCapture.toString()).contains(
|
||||
"Passed username and password - will set a custom credentials provider");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_not_push_changes_to_current_branch_when_no_changes_were_made() throws Exception {
|
||||
public void should_not_push_changes_to_current_branch_when_no_changes_were_made()
|
||||
throws Exception {
|
||||
this.updater.updateContractProject("hello-world", this.origin.toPath());
|
||||
|
||||
try(Git git = openGitProject(this.project)) {
|
||||
try (Git git = openGitProject(this.project)) {
|
||||
RevCommit revCommit = git.log().call().iterator().next();
|
||||
then(revCommit.getShortMessage()).isEqualTo("Initial commit");
|
||||
}
|
||||
BDDAssertions.then(new File(this.project, "META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json")).doesNotExist();
|
||||
BDDAssertions.then(new File(this.project,
|
||||
"META-INF/com.example/hello-world/0.0.2/mappings/someMapping.json"))
|
||||
.doesNotExist();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,17 +31,19 @@ import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.assertj.core.api.BDDAssertions.thenThrownBy;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
* taken from: https://github.com/spring-cloud/spring-cloud-release-tools
|
||||
* @author Marcin Grzejszczak taken from:
|
||||
* https://github.com/spring-cloud/spring-cloud-release-tools
|
||||
*/
|
||||
public class GitRepoTests extends AbstractGitTest {
|
||||
|
||||
File project;
|
||||
|
||||
GitRepo gitRepo;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException, URISyntaxException {
|
||||
this.project = new File(GitRepoTests.class.getResource("/git_samples/contract-git").toURI());
|
||||
this.project = new File(
|
||||
GitRepoTests.class.getResource("/git_samples/contract-git").toURI());
|
||||
TestUtils.prepareLocalRepo();
|
||||
this.gitRepo = new GitRepo(this.tmpFolder);
|
||||
}
|
||||
@@ -54,19 +56,22 @@ public class GitRepoTests extends AbstractGitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_throw_exception_when_there_is_no_repo() throws IOException, URISyntaxException {
|
||||
public void should_throw_exception_when_there_is_no_repo()
|
||||
throws IOException, URISyntaxException {
|
||||
thenThrownBy(() -> this.gitRepo
|
||||
.cloneProject(GitRepoTests.class.getResource("/git_samples/").toURI()))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Exception occurred while cloning repo");
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Exception occurred while cloning repo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_throw_an_exception_when_failed_to_initialize_the_repo() throws IOException {
|
||||
thenThrownBy(() -> new GitRepo(this.tmpFolder, new ExceptionThrowingJGitFactory()).cloneProject(this.project.toURI()))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Exception occurred while cloning repo")
|
||||
.hasCauseInstanceOf(CustomException.class);
|
||||
public void should_throw_an_exception_when_failed_to_initialize_the_repo()
|
||||
throws IOException {
|
||||
thenThrownBy(() -> new GitRepo(this.tmpFolder, new ExceptionThrowingJGitFactory())
|
||||
.cloneProject(this.project.toURI()))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Exception occurred while cloning repo")
|
||||
.hasCauseInstanceOf(CustomException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -79,12 +84,14 @@ public class GitRepoTests extends AbstractGitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_throw_an_exception_when_checking_out_nonexisting_branch() throws IOException {
|
||||
public void should_throw_an_exception_when_checking_out_nonexisting_branch()
|
||||
throws IOException {
|
||||
File project = this.gitRepo.cloneProject(this.project.toURI());
|
||||
try {
|
||||
this.gitRepo.checkout(project, "nonExistingBranch");
|
||||
fail("should throw an exception");
|
||||
} catch (IllegalStateException e) {
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
then(e).hasMessageContaining("Ref nonExistingBranch can not be resolved");
|
||||
}
|
||||
}
|
||||
@@ -96,7 +103,7 @@ public class GitRepoTests extends AbstractGitTest {
|
||||
|
||||
this.gitRepo.commit(project, "some message");
|
||||
|
||||
try(Git git = openGitProject(project)) {
|
||||
try (Git git = openGitProject(project)) {
|
||||
RevCommit revCommit = git.log().call().iterator().next();
|
||||
then(revCommit.getShortMessage()).isEqualTo("some message");
|
||||
}
|
||||
@@ -120,7 +127,7 @@ public class GitRepoTests extends AbstractGitTest {
|
||||
|
||||
this.gitRepo.commit(project, "empty commit");
|
||||
|
||||
try(Git git = openGitProject(project)) {
|
||||
try (Git git = openGitProject(project)) {
|
||||
RevCommit revCommit = git.log().call().iterator().next();
|
||||
then(revCommit.getShortMessage()).isNotEqualTo("empty commit");
|
||||
}
|
||||
@@ -136,7 +143,7 @@ public class GitRepoTests extends AbstractGitTest {
|
||||
|
||||
this.gitRepo.pushCurrentBranch(project);
|
||||
|
||||
try(Git git = openGitProject(origin)) {
|
||||
try (Git git = openGitProject(origin)) {
|
||||
RevCommit revCommit = git.log().call().iterator().next();
|
||||
then(revCommit.getShortMessage()).isEqualTo("some message");
|
||||
}
|
||||
@@ -152,21 +159,27 @@ public class GitRepoTests extends AbstractGitTest {
|
||||
|
||||
this.gitRepo.pull(project);
|
||||
|
||||
try(Git git = openGitProject(project)) {
|
||||
try (Git git = openGitProject(project)) {
|
||||
RevCommit revCommit = git.log().call().iterator().next();
|
||||
then(revCommit.getShortMessage()).isEqualTo("some message");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ExceptionThrowingJGitFactory extends GitRepo.JGitFactory {
|
||||
@Override CloneCommand getCloneCommandByCloneRepository() {
|
||||
|
||||
@Override
|
||||
CloneCommand getCloneCommandByCloneRepository() {
|
||||
throw new CustomException("foo");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CustomException extends RuntimeException {
|
||||
|
||||
public CustomException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,7 +31,9 @@ import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
public class GitStubDownloaderTests {
|
||||
|
||||
@Rule public TemporaryFolder tmp = new TemporaryFolder();
|
||||
@Rule
|
||||
public TemporaryFolder tmp = new TemporaryFolder();
|
||||
|
||||
File temporaryFolder;
|
||||
|
||||
@Before
|
||||
@@ -45,10 +47,10 @@ public class GitStubDownloaderTests {
|
||||
public void should_return_a_null_downloader_for_a_classptath_mode() {
|
||||
StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder();
|
||||
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.CLASSPATH)
|
||||
.withProperties(props())
|
||||
.build());
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder
|
||||
.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.CLASSPATH)
|
||||
.withProperties(props()).build());
|
||||
|
||||
then(stubDownloader).isNull();
|
||||
}
|
||||
@@ -57,10 +59,10 @@ public class GitStubDownloaderTests {
|
||||
public void should_return_a_null_downloader_for_a_empty_repo() {
|
||||
StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder();
|
||||
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withProperties(props())
|
||||
.build());
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder
|
||||
.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withProperties(props()).build());
|
||||
|
||||
then(stubDownloader).isNull();
|
||||
}
|
||||
@@ -69,46 +71,54 @@ public class GitStubDownloaderTests {
|
||||
public void should_return_a_null_downloader_for_a_non_git_repo() {
|
||||
StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder();
|
||||
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withStubRepositoryRoot("http://foo.com")
|
||||
.withProperties(props())
|
||||
.build());
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder
|
||||
.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withStubRepositoryRoot("http://foo.com").withProperties(props())
|
||||
.build());
|
||||
|
||||
then(stubDownloader).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_pick_stubs_for_group_and_artifact_with_version_from_a_git_repo() throws Exception {
|
||||
public void should_pick_stubs_for_group_and_artifact_with_version_from_a_git_repo()
|
||||
throws Exception {
|
||||
StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder();
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withStubRepositoryRoot("git://" + file("/git_samples/contract-git/").getAbsolutePath() + "/")
|
||||
.withProperties(props())
|
||||
.build());
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder
|
||||
.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withStubRepositoryRoot("git://"
|
||||
+ file("/git_samples/contract-git/").getAbsolutePath()
|
||||
+ "/")
|
||||
.withProperties(props()).build());
|
||||
|
||||
Map.Entry<StubConfiguration, File> entry = stubDownloader
|
||||
.downloadAndUnpackStubJar(new StubConfiguration("foo.bar:bazService:0.0.1-SNAPSHOT"));
|
||||
.downloadAndUnpackStubJar(
|
||||
new StubConfiguration("foo.bar:bazService:0.0.1-SNAPSHOT"));
|
||||
|
||||
then(entry).isNotNull();
|
||||
then(entry.getValue().getAbsolutePath()).contains("foo.bar" + File.separator + "bazService" + File.separator + "0.0.1-SNAPSHOT");
|
||||
then(entry.getValue().getAbsolutePath()).contains("foo.bar" + File.separator
|
||||
+ "bazService" + File.separator + "0.0.1-SNAPSHOT");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_fail_to_fetch_stubs_when_latest_version_was_specified()
|
||||
throws URISyntaxException {
|
||||
StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder();
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withStubRepositoryRoot("git://" + file("/git_samples/contract-git").getAbsolutePath())
|
||||
.withProperties(props())
|
||||
.build());
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder
|
||||
.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withStubRepositoryRoot("git://"
|
||||
+ file("/git_samples/contract-git").getAbsolutePath())
|
||||
.withProperties(props()).build());
|
||||
|
||||
try {
|
||||
stubDownloader
|
||||
.downloadAndUnpackStubJar(new StubConfiguration("foo.bar:bazService:+"));
|
||||
} catch (IllegalStateException e) {
|
||||
then(e).hasMessageContaining("Concrete version wasn't passed for [foo.bar:bazService:+:stubs]");
|
||||
stubDownloader.downloadAndUnpackStubJar(
|
||||
new StubConfiguration("foo.bar:bazService:+"));
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
then(e).hasMessageContaining(
|
||||
"Concrete version wasn't passed for [foo.bar:bazService:+:stubs]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,17 +126,20 @@ public class GitStubDownloaderTests {
|
||||
public void should_fail_to_fetch_stubs_when_concrete_version_was_not_specified()
|
||||
throws URISyntaxException {
|
||||
StubDownloaderBuilder stubDownloaderBuilder = new ScmStubDownloaderBuilder();
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withStubRepositoryRoot("git://" + file("/git_samples/contract-git").getAbsolutePath())
|
||||
.withProperties(props())
|
||||
.build());
|
||||
StubDownloader stubDownloader = stubDownloaderBuilder
|
||||
.build(new StubRunnerOptionsBuilder()
|
||||
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
|
||||
.withStubRepositoryRoot("git://"
|
||||
+ file("/git_samples/contract-git").getAbsolutePath())
|
||||
.withProperties(props()).build());
|
||||
|
||||
try {
|
||||
stubDownloader
|
||||
.downloadAndUnpackStubJar(new StubConfiguration("foo.bar", "bazService", ""));
|
||||
} catch (IllegalStateException e) {
|
||||
then(e).hasMessageContaining("Concrete version wasn't passed for [foo.bar:bazService::stubs]");
|
||||
stubDownloader.downloadAndUnpackStubJar(
|
||||
new StubConfiguration("foo.bar", "bazService", ""));
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
then(e).hasMessageContaining(
|
||||
"Concrete version wasn't passed for [foo.bar:bazService::stubs]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,4 +152,5 @@ public class GitStubDownloaderTests {
|
||||
private File file(String relativePath) throws URISyntaxException {
|
||||
return new File(GitStubDownloaderTests.class.getResource(relativePath).toURI());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user