I have some Groovy 2.4.x code that uses some JDBC:
class WidgetPersistor {
#Inject // Gets injected correctly by Guice, don't worry about it!
DataSource dataSource
Fizz getFizzByWidgetName(String name) {
Connection conn
PreparedStatement ps
ResultSet rs
try {
// JDBC code here
} catch(SQLException sqlExc) {
if(conn) {
try {
// NOTE: At the end of the day, I just want to verify
// that, given the 'name' arg to this method, the rollback
// doesn't fire!
conn.rollback()
} catch(SQLException rollBackExc) {
throw rollBackExc
}
}
throw sqlExc
} finally {
if(conn) {
try {
rs.close()
ps.close()
conn.close()
} catch(SQLException closingExc) {
throw closingExc
}
}
}
}
}
I am trying to write a Spock test that will execute this getFizzByWidgetName method and verify that the conn.rollback() method never executed (meaning we never tried to rollback).
Here's my best attempt:
def "getFizzByWidgetName succeeds without rollback"() {
given: "data client with db connections"
// Don't worry about how I get this for my test, but its a legit JDBC connection
DataSource ds = provideDataSource()
Connection mockConn = Mock(Connection)
PreparedStatement mockPS = Mock(PreparedStatement)
ResultSet mockRS = Mock(ResultSet)
mockPS.executeQuery() >> mockRS
mockConn.prepareStatement(_) >> mockPS
ds.connection >> mockConn // ??? Its like I want the DataSource half-mocked...
WidgetPersistor client = new WidgetPersistor(mockDS)
when: "we try to query something"
client.getFizzByWidgetName('fizzbuzz')
then: "we dont get any errors"
0 * mockConn.rollback()
}
Any ideas where I'm going awry?
If you are using a DataSource from a real database, and your code under test is written in Groovy (which looks like the case), you can use the metaclass to test this kind of things:
DataSource ds = provideDataSource()
def connection = ds.connection
connection.metaClass.rollback = { throw new AssertionError("rollback called") }
ds.metaClass.connection = connection
But it's not really pretty. You should probably call your method without using mocks, and test the state of the database (ie, data have been committed, not rollbacked)
Related
I'm exposing a simple SSE endpoint using the SseEmitter Spring API, persisting all the emitters in a ConcurrentHashMap. The timeout for each emitter is set to 24 hours. Every 10 seconds I'm sending a message to all the clients. Clients are subscribed with native EventSource implementation, listening for events of particular name.
Unfortunately, I've noticed that every 5 minutes the connection is lost and reestablished again - even though timeout of emitter was explicitly set to 24 hours. Client's part does log it as an error, however on server side there's nothing. The issue occurs on both Tomcat and Jetty. I'd like to keep the session open without any interruptions, so resetting the connection every 5 minutes is unacceptable. Any ideas why this could be happening?
#RestController
#RequestMapping("api/v1/sse")
class SseController {
private val emitters = ConcurrentHashMap<String, SseEmitter>()
#GetMapping
fun initConnection(#RequestParam token: String): SseEmitter {
logger.info { "Init connection from $token" }
val emitter = SseEmitter(24 * 60 * 60 * 1000)
emitter.onCompletion {
logger.info { "Completion" }
emitters.remove(token)
}
emitter.onTimeout { logger.info { "Timeout " } }
emitter.onError { logger.error(it) { "Error" } }
emitters[token] = emitter
return emitter
}
#Scheduled(fixedRate = 10000)
fun send() {
emitters.forEach { (k, v) ->
logger.info { "Sending message to $k" }
v.send(
SseEmitter.event()
.id(UUID.randomUUID().toString())
.name("randomEvent")
.data("some data")
)
}
}
}
const eventSource = new EventSource(url);
eventSource.addEventListener('randomEvent', (e) =>
console.log(e.data)
);
eventSource.onerror = (e) => console.log(e);
Alright, seems it was an issue with Stackblitz's service worker. I've just implemented the same client-side solution in Chrome's plain console and the disconnecting is no longer happening.
I believe I am missing/misunderstanding something fundamental about the way .net5 works. In setting up an integration test environment for my GraphQL API, I am missing the step on how to start the GraphQL server from said test environment.
When I run the main project, the server is started properly and I can navigate to localhost in the browser and successfully execute GraphQL queries/mutations. My goal here is to set up some automated integration tests.
I'm using NUnit as my test runner and am using WebApplicationFactory<Startup> to "start the server" as I understand it.
In my test project, I'm under the impression that WebApplicationFactory<Startup> is supposed to basically use the Startup.cs class from my main project in my test project so that I don't have to duplicate all the settings, configurations, and injected services. Please correct me if that assumption is not correct.
I've pasted the code I think is relevant.
ApiWebApplicationFactory<Startup>
public class ApiWebApplicationFactory<TStartup> : WebApplicationFactory<Startup> where TStartup : class
{
public static IConfigurationRoot Configuration { get; set; }
public ApiWebApplicationFactory()
{
var configBuilder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
Configuration = configBuilder.Build();
}
protected override void ConfigureClient(HttpClient client)
{
base.ConfigureClient(client);
client.BaseAddress = new Uri("https://localhost");
client.Timeout = new TimeSpan(0, 10, 0);
}
// Based on my assumption this class reuses everything in the Startup.cs class
// I don't actually think this is necessary, but thought it was worth trying
// the test with and without this code.
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddType<GraphQLContentItem>()
.AddType<GraphQLFolder>();
});
}
}
OneTimesetUp
[OneTimeSetUp]
public void OneTimeSetUp()
{
_factory = new ApiWebApplicationFactory<Startup>();
_client = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
services.AddScoped<ICacheRepository, MockCache>();
});
}).CreateClient();
var connString = ApiWebApplicationFactory<Startup>.Configuration.GetConnectionString("DefaultConnection");
var options = new DbContextOptionsBuilder<CmsContext>()
.UseMySql(connString, ServerVersion.AutoDetect(connString))
.Options;
_dbContext = new CmsContext(options);
_dbContext.Database.EnsureCreated();
}
Test
[Test]
public async Task Test()
{
// If I set a breakpoint here, I can't navigate to the URL like I'm expecting to
var graphQLHttpClient =
new GraphQLHttpClient(
new GraphQLHttpClientOptions { EndPoint = new Uri("https://localhost/graphql") },
new NewtonsoftJsonSerializer(),
_client);
var request = new GraphQLRequest
{
Query = #"
query GetCurrentSession() {
getCurrentSession() {
id
name
}
}",
OperationName = "GetCurrentSession"
};
// Error is thrown here with "Bad Request"
var response = await graphQLHttpClient.SendQueryAsync<Session>(request);
// Further code is omitted
}
Please let me know if you see what I am missing. Thanks in advance~
Deployed web application in weblogic 12c server and it has data source configure to make use of connection pool.
Database is Oracle 12,
Usecase: when application is alive up and running, for a min database backup script has been run(stop db, backup, start db), after that when trying to access application(session got established) then got SQL error (connection already closed). What could be an issue?
Temporary solution: after restarting application it was working fine with out any issue. Still wondering how it got worked?
Datasource configuration :
**dataSource {
configClass = GrailsAnnotationConfiguration.class
dialect = "org.hibernate.dialect.Oracle10gDialect"
loggingSql = false
jmxExport = false
}
hibernate {
cache.use_second_level_cache = true
cache.use_query_cache = true
cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
hbm2ddl.auto = null
show_sql = false
// naming_strategy = "org.hibernate.cfg.ImprovedNamingStrategy"
dialect = "org.hibernate.dialect.Oracle10gDialect"
config.location = [
"classpath:hibernate-core.cfg.xml",
"classpath:hibernate-utility.cfg.xml"
]
}
// environment specific settings
environments {
development {
dataSource {
}
}
test {
dataSource {
}
}
production {
dataSource {
}
}
}**
I am using java 1.8 and oracle 12c versions in my application. As part of this I have below code to close the statement.
protected static void close(Statement p_stmt)
throws DAOException
{
if (p_stmt != null) {
try {
p_stmt.close();
} catch (SQLException sqle) {
m_logger.error("Error closing statement", sqle);
throw new DAOException("Error closing statement", sqle);
}
}
}
When this method executes, I am facing the below error but it is not happening consistently.
Error closing statement
java.sql.SQLRecoverableException: Closed Connection
at oracle.jdbc.driver.PhysicalConnection.needLine(PhysicalConnection.java:4220)
at oracle.jdbc.driver.OracleStatement.closeOrCache(OracleStatement.java:1431)
at oracle.jdbc.driver.OracleStatement.close(OracleStatement.java:1410)
at oracle.jdbc.driver.OracleStatementWrapper.close(OracleStatementWrapper.java:102)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.close(OraclePreparedStatementWrapper.java:82)
Could I get some help to figure out the root cause of this issue?
My calling code is:
finally
{
// do not close the connection here
close(result);
close(stmt);
}
Please let me know for more information
Use try-with-resource statement instead of manually closing statement, resultset and connection like that:
try (Connection con = DriverManager.getConnection(myConnectionURL);
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setxxx();
try (ResultSet rs = ps.executeQuery()) {
<your code to process results>
}
} catch (SQLException e) {
e.printStackTrace();
}
I'm using Grails Spring Security Core and the Grails Spring Security REST plugin and I'm just starting to get things set up. I initialized the plugins with a User class and an Authority class (defaults) and went to write an integration test, following a guide I found on the Grails website.
It said to put the following in an integration test:
def "test a user with the role ROLE_BOSS is able to access /api/announcements url"() {
when: 'login with the sherlock'
RestBuilder rest = new RestBuilder()
def resp = rest.post("http://localhost:${serverPort}/api/login") {
accept('application/json')
contentType('application/json')
json {
username = 'sherlock'
password = 'elementary'
}
}
then:
resp.status == 200
resp.json.roles.find { it == 'ROLE_BOSS' }
}
I went ahead and did something similar and it worked with a bootstrapped User, but when I tried to do the exact same test with a User created in the test method itself, it would fail with a 401 HTTP response code.
The code I'm trying to run:
void "check get access token"() {
given:
RestBuilder rest = new RestBuilder()
new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
assert User.count == 2
when:
def resp = rest.post("http://localhost:${serverPort}/api/login") {
accept('application/json')
contentType('application/json')
json {
username = "securitySpecTestUserName"
password = "securitySpecTestPassword"
}
}
then:
resp.status == 200
}
Note that the User.count == 2 assertion passes because there is one User in Bootstrap.groovy and the one create in the test method.
Why does this work and pass with the bootstrapped User without any issues at all but not the one created in the method? Is there a way I can write this integration test so that I can test the /api/login endpoint included in the grails-spring-security-rest plugin in this way?
The User you create in the given section is in a transaction that has not been committed. When you make the REST call, the api/login controller will be run in a new transaction that cannot see your un-committed User.
A few options (there are others)...
Create User in BootStrap.groovy
def init = { servletContext ->
environments {
test {
new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
}
}
}
Make REST calls to create the User - assuming you have such functionality
Create User in setup
#Integration
#Rollback
class UserIntSpec extends Specification {
def setup() {
new User(username: "securitySpecTestUserName", password: "securitySpecTestPassword").save(flush: true)
}
void "check get access token"() {
given:
RestBuilder rest = new RestBuilder()
when:
def response = rest.post("http://localhost:${serverPort}/api/login") {
accept('application/json')
contentType('application/json')
json {
username = "securitySpecTestUserName"
password = "securitySpecTestPassword"
}
}
then:
response.status == HttpServletResponse.SC_OK
when:
def token = response.json.access_token
then:
token
}
}
Note: In Grails >= 3.0, setup() is run in a separate transaction and persisted (why it solves your problem) which is not rolled back. Any data will need to be cleaned up manually.
I suggest you read the grails documentation on testing: Integration Testing