Skip to content

Commit

Permalink
Find the lost transaction manager (#1323)
Browse files Browse the repository at this point in the history
As part of #620, the transaction manager autoconfiguration was removed from the main Firestore autoconfig but was not added to Spring's metadata, so it's not automatically loaded.

This PR:

Brings back the transaction manager in spring.factories (we'll have to re-add for the New Way in Boot 3.0).
Adds a service between controller and repository, but for only one method.
Strengthens the test by verifying that HTTP call does not fail, but only for one method.
  • Loading branch information
elefeint authored Nov 8, 2022
1 parent 6549e25 commit 91aef6f
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ com.google.cloud.spring.autoconfigure.spanner.health.SpannerHealthIndicatorAutoC
com.google.cloud.spring.autoconfigure.spanner.SpannerTransactionManagerAutoConfiguration,\
com.google.cloud.spring.autoconfigure.datastore.GcpDatastoreAutoConfiguration,\
com.google.cloud.spring.autoconfigure.firestore.GcpFirestoreAutoConfiguration,\
com.google.cloud.spring.autoconfigure.firestore.FirestoreTransactionManagerAutoConfiguration,\
com.google.cloud.spring.autoconfigure.firestore.GcpFirestoreEmulatorAutoConfiguration,\
com.google.cloud.spring.autoconfigure.datastore.health.DatastoreHealthIndicatorAutoConfiguration,\
com.google.cloud.spring.autoconfigure.storage.GcpStorageAutoConfiguration,\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@
<artifactId>gcloud</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;

/** Sample application for Spring Data Firestore. */
@SpringBootApplication
@EnableTransactionManagement
public class FirestoreSampleApplication {

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ public class UserController {

private final FirestoreTemplate firestoreTemplate;

public UserController(UserRepository userRepository, FirestoreTemplate firestoreTemplate) {
private final UserService userService;

public UserController(UserService userService, UserRepository userRepository, FirestoreTemplate firestoreTemplate) {
this.userService = userService;
this.userRepository = userRepository;
this.firestoreTemplate = firestoreTemplate;
}
Expand All @@ -62,9 +65,7 @@ private Flux<PhoneNumber> getPhonesByName(@RequestParam String name) {

@GetMapping("/removeUser")
private Mono<String> removeUserByName(@RequestParam String name) {
return this.userRepository
.delete(new User(name, 0, null))
.map(unusedVoid -> name + "was successfully removed");
return this.userService.removeUserByName(name);
}

@GetMapping("/removePhonesForUser")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2022-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Mono;

@Service
public class UserService {

private final UserRepository userRepository;

public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}

// Testing that Transactional works;
// see https://github.com/GoogleCloudPlatform/spring-cloud-gcp/issues/1297
@Transactional
public Mono<String> removeUserByName(String name) {
return userRepository
.delete(new User(name, 0, null))
.map(unusedVoid -> name + "was successfully removed");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@

package com.example;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.assertj.core.api.Assertions;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
Expand All @@ -38,25 +43,27 @@ public TestUserClient(RestTemplate restTemplate) {

public List<User> listUsers() {
User[] users = restTemplate.getForObject("/users", User[].class);
Assertions.assertThat(users).isNotNull();
assertThat(users).isNotNull();
return Arrays.asList(users);
}

public List<User> findUsersByAge(int age) {
User[] users = restTemplate.getForObject("/users/age?age=" + age, User[].class);
Assertions.assertThat(users).isNotNull();
assertThat(users).isNotNull();
return Arrays.asList(users);
}

public List<PhoneNumber> listPhoneNumbers(String name) {
PhoneNumber[] phoneNumbers =
restTemplate.getForObject("/users/phones?name=" + name, PhoneNumber[].class);
Assertions.assertThat(phoneNumbers).isNotNull();
assertThat(phoneNumbers).isNotNull();
return Arrays.asList(phoneNumbers);
}

public void removeUserByName(String name) {
restTemplate.getForEntity("/users/removeUser?name=" + name, String.class);
ResponseEntity<String> response =
restTemplate.getForEntity("/users/removeUser?name=" + name, String.class);
assertThat(response.getStatusCode()).isSameAs(HttpStatus.OK);
}

public void removePhonesForUser(String name) {
Expand Down

0 comments on commit 91aef6f

Please sign in to comment.