Skip to content

Commit

Permalink
Add tests for timeout and lifetime checks
Browse files Browse the repository at this point in the history
  • Loading branch information
ali-ince committed Oct 5, 2018
1 parent 1371a71 commit 1e44f97
Show file tree
Hide file tree
Showing 7 changed files with 333 additions and 4 deletions.
1 change: 0 additions & 1 deletion neo4j/config_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,3 @@ func wrapAddressResolverOrNil(addressResolver ServerAddressResolver) gobolt.UrlA
return result
}
}

104 changes: 104 additions & 0 deletions neo4j/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package neo4j

import (
"math"
"time"

. "github.com/onsi/ginkgo"
Expand All @@ -34,10 +35,42 @@ var _ = Describe("Config", func() {
Expect(config.Encrypted).To(BeTrue())
})

It("should have trust strategy equal to TrustAny(false)", func() {
Expect(config.TrustStrategy).To(Equal(TrustAny(false)))
})

It("should have max transaction retry duration as 30s", func() {
Expect(config.MaxTransactionRetryTime).To(BeIdenticalTo(30 * time.Second))
})

It("should have max connection pool size to be 100", func() {
Expect(config.MaxConnectionPoolSize).To(BeEquivalentTo(100))
})

It("should have max connection lifetime to be 1h", func() {
Expect(config.MaxConnectionLifetime).To(BeIdenticalTo(1 * time.Hour))
})

It("should have connection acquisition timeout to be 1m", func() {
Expect(config.ConnectionAcquisitionTimeout).To(BeIdenticalTo(1 * time.Minute))
})

It("should have socket connect timeout to be 5s", func() {
Expect(config.SocketConnectTimeout).To(BeIdenticalTo(5 * time.Second))
})

It("should have socket receive timeout to be 0", func() {
Expect(config.SocketReceiveTimeout).To(BeIdenticalTo(0 * time.Second))
})

It("should have socket send timeout to be 0", func() {
Expect(config.SocketSendTimeout).To(BeIdenticalTo(0 * time.Second))
})

It("should have socket keep alive enabled", func() {
Expect(config.SocketKeepalive).To(BeTrue())
})

It("should have non-nil logger", func() {
Expect(config.Log).NotTo(BeNil())
})
Expand All @@ -49,4 +82,75 @@ var _ = Describe("Config", func() {
Expect(logger.level).To(BeZero())
})
})

Context("validateAndNormaliseConfig", func() {
It("should return error when MaxTransactionRetryTime is less than 0", func() {
config := defaultConfig()
config.MaxTransactionRetryTime = -1 * time.Second

err := validateAndNormaliseConfig(config)
Expect(err).NotTo(BeNil())
Expect(err.Error()).To(ContainSubstring("maximum transaction retry time cannot be smaller than 0"))
})

It("should return error when MaxConnectionPoolSize is 0", func() {
config := defaultConfig()
config.MaxConnectionPoolSize = 0

err := validateAndNormaliseConfig(config)
Expect(err).NotTo(BeNil())
Expect(err.Error()).To(ContainSubstring("maximum connection pool size cannot be 0"))
})

It("should normalize MaxConnectionPoolSize to MaxInt32 when negative", func() {
config := defaultConfig()
config.MaxConnectionPoolSize = -1

err := validateAndNormaliseConfig(config)
Expect(err).To(BeNil())

Expect(config.MaxConnectionPoolSize).To(Equal(math.MaxInt32))
})

It("should normalize ConnectionAcquisitionTimeout to -1ns when negative", func() {
config := defaultConfig()
config.ConnectionAcquisitionTimeout = -1 * time.Second

err := validateAndNormaliseConfig(config)
Expect(err).To(BeNil())

Expect(config.ConnectionAcquisitionTimeout).To(Equal(-1 * time.Nanosecond))
})

It("should normalize SocketConnectTimeout to 0 when negative", func() {
config := defaultConfig()
config.SocketConnectTimeout = -1 * time.Second

err := validateAndNormaliseConfig(config)
Expect(err).To(BeNil())

Expect(config.SocketConnectTimeout).To(Equal(0 * time.Nanosecond))
})

It("should normalize SocketReceiveTimeout to 0 when negative", func() {
config := defaultConfig()
config.SocketReceiveTimeout = -1 * time.Second

err := validateAndNormaliseConfig(config)
Expect(err).To(BeNil())

Expect(config.SocketReceiveTimeout).To(Equal(0 * time.Nanosecond))
})

It("should normalize SocketSendTimeout to 0 when negative", func() {
config := defaultConfig()
config.SocketSendTimeout = -1 * time.Second

err := validateAndNormaliseConfig(config)
Expect(err).To(BeNil())

Expect(config.SocketSendTimeout).To(Equal(0 * time.Nanosecond))
})
})

})
1 change: 0 additions & 1 deletion neo4j/test-integration/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ var _ = Describe("Examples", func() {
Expect(err).To(BeNil())
})


Specify("Service Unavailable", func() {
driver, err := createDriverWithMaxRetryTime("bolt://localhost:8080", username, password)
Expect(err).To(BeNil())
Expand Down
166 changes: 166 additions & 0 deletions neo4j/test-integration/timeout_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* Copyright (c) 2002-2018 "Neo4j,"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package test_integration

import (
"time"

"github.com/neo4j/neo4j-go-driver/neo4j"
"github.com/neo4j/neo4j-go-driver/neo4j/test-integration/control"
"github.com/neo4j/neo4j-go-driver/neo4j/test-integration/utils"
"github.com/neo4j/neo4j-go-driver/neo4j/utils/test"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Timeout and Lifetime", func() {
var err error
var log *utils.MemoryLogging
var server *control.SingleInstance

BeforeEach(func() {
log = &utils.MemoryLogging{}

server, err = control.EnsureSingleInstance()
Expect(err).To(BeNil())
Expect(server).NotTo(BeNil())
})

It("should error when ConnectionAcquisitionTimeout is hit", func() {
var err error
var driver neo4j.Driver
var session1, session2 neo4j.Session

driver, err = neo4j.NewDriver(server.BoltUri(), server.AuthToken(), server.Config(), func(config *neo4j.Config) {
config.Log = log
config.ConnectionAcquisitionTimeout = 1 * time.Second
config.MaxConnectionPoolSize = 1
})
Expect(err).To(BeNil())
Expect(driver).NotTo(BeNil())
defer driver.Close()

session1, _ = newSessionAndTx(driver, neo4j.AccessModeRead)
defer session1.Close()

session2, err = driver.Session(neo4j.AccessModeRead)
Expect(err).To(BeNil())
Expect(session2).NotTo(BeNil())
defer session2.Close()

_, err = session2.Run("RETURN 1", nil)
Expect(err).To(test.BeConnectorErrorWithCode(0x601))
})

It("should close connection when MaxConnectionLifetime is hit", func() {
var err error
var driver neo4j.Driver
var session1, session2 neo4j.Session

driver, err = neo4j.NewDriver(server.BoltUri(), server.AuthToken(), server.Config(), func(config *neo4j.Config) {
config.Log = log
config.MaxConnectionLifetime = 5 * time.Second
config.MaxConnectionPoolSize = 1
})
Expect(err).To(BeNil())
Expect(driver).NotTo(BeNil())
defer driver.Close()

session1, _ = newSessionAndTx(driver, neo4j.AccessModeRead)
time.Sleep(5 * time.Second)
session1.Close()

session2, _ = newSessionAndTx(driver, neo4j.AccessModeRead)
defer session2.Close()

Expect(log.Infos).Should(ContainElement(ContainSubstring("reached its maximum lifetime")))
})

It("should timeout connection when SocketConnectTimeout is hit", func() {
var err error
var driver neo4j.Driver
var session neo4j.Session

driver, err = neo4j.NewDriver("bolt://192.168.0.0:8080", server.AuthToken(), server.Config(), func(config *neo4j.Config) {
config.Log = log
config.SocketConnectTimeout = 5 * time.Second
})
Expect(err).To(BeNil())
Expect(driver).NotTo(BeNil())
defer driver.Close()

session = newSession(driver, neo4j.AccessModeRead)
defer session.Close()

_, err = session.BeginTransaction()
Expect(err).To(test.BeConnectorErrorWithCode(6))
})

It("should timeout receive when SocketReceiveTimeout is hit on encrypted connection", func() {
var err error
var driver neo4j.Driver
var session neo4j.Session
var result neo4j.Result

driver, err = neo4j.NewDriver(server.BoltUri(), server.AuthToken(), server.Config(), func(config *neo4j.Config) {
config.Log = log
config.SocketReceiveTimeout = 1 * time.Second
})
Expect(err).To(BeNil())
Expect(driver).NotTo(BeNil())
defer driver.Close()

session = newSession(driver, neo4j.AccessModeRead)
defer session.Close()

result, err = session.Run("UNWIND RANGE(1,100000000) AS N RETURN SUM(N)", nil)
Expect(err).To(BeNil())

_, err = result.Consume()
Expect(err).To(test.BeConnectorErrorWithCode(6))
})

It("should timeout receive when SocketReceiveTimeout is hit on plaintext connection", func() {
var err error
var driver neo4j.Driver
var session neo4j.Session
var result neo4j.Result

driver, err = neo4j.NewDriver(server.BoltUri(), server.AuthToken(), server.Config(), func(config *neo4j.Config) {
config.Encrypted = false
config.Log = log
config.SocketReceiveTimeout = 1 * time.Second
})
Expect(err).To(BeNil())
Expect(driver).NotTo(BeNil())
defer driver.Close()

session = newSession(driver, neo4j.AccessModeRead)
defer session.Close()

result, err = session.Run("UNWIND RANGE(1,100000000) AS N RETURN SUM(N)", nil)
Expect(err).To(BeNil())

_, err = result.Consume()
Expect(err).To(test.BeConnectorErrorWithCode(6))
})

})
61 changes: 61 additions & 0 deletions neo4j/test-integration/utils/mem_log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2002-2018 "Neo4j,"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package utils

import "fmt"

type MemoryLogging struct {
Errors []string
Warnings []string
Infos []string
Debugs []string
}

func (log *MemoryLogging) ErrorEnabled() bool {
return true
}

func (log *MemoryLogging) WarningEnabled() bool {
return true
}

func (log *MemoryLogging) InfoEnabled() bool {
return true
}

func (log *MemoryLogging) DebugEnabled() bool {
return true
}

func (log *MemoryLogging) Errorf(message string, args ...interface{}) {
log.Errors = append(log.Errors, fmt.Sprintf(message, args...))
}

func (log *MemoryLogging) Warningf(message string, args ...interface{}) {
log.Warnings = append(log.Warnings, fmt.Sprintf(message, args...))
}

func (log *MemoryLogging) Infof(message string, args ...interface{}) {
log.Infos = append(log.Infos, fmt.Sprintf(message, args...))
}

func (log *MemoryLogging) Debugf(message string, args ...interface{}) {
log.Debugs = append(log.Debugs, fmt.Sprintf(message, args...))
}
2 changes: 1 addition & 1 deletion neo4j/test-stub/control/boltstub.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (server *StubServer) markExited() {
}

func (server *StubServer) exited() bool {
return atomic.LoadInt32(&server.stubExited) == 1;
return atomic.LoadInt32(&server.stubExited) == 1
}

func (server *StubServer) markExitError(text string) {
Expand Down
2 changes: 1 addition & 1 deletion neo4j/test-stub/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@ func logLevel() neo4j.LogLevel {
}

return neo4j.ERROR
}
}

0 comments on commit 1e44f97

Please sign in to comment.