Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fix: Mark connection as not good when error on cancellation confirmation #68

Merged
merged 5 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions queries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -1387,6 +1388,46 @@ func TestProcessQueryErrors(t *testing.T) {
}
}

type mockReadWriteCloser struct {
io.ReadWriteCloser
}

func (*mockReadWriteCloser) Read([]byte) (int, error) { return 0, errors.New("fake err") }

func TestProcessQueryCancelConfirmationError(t *testing.T) {
tl := testLogger{t: t}
defer tl.StopLogging()
conn := internalConnection(t, &tl)
defer conn.Close()

stmt, err := conn.prepareContext(context.Background(), "select 1")
if err != nil {
t.Fatal("prepareContext expected to succeed, but it failed with", err)
}
err = stmt.sendQuery(context.Background(), []namedValue{})
if err != nil {
t.Fatal("sendQuery expected to succeed, but it failed with", err)
}
// mock real connection to imitate situation when you write but dont get response
conn.sess.buf.transport = &mockReadWriteCloser{ReadWriteCloser: conn.sess.buf.transport}
// canceling context to try to send attention request
ctx, cancel := context.WithCancel(context.Background())
cancel()

_, err = stmt.processQueryResponse(ctx)
if err == nil {
t.Error("processQueryResponse expected to fail but it succeeded")
}
// should not fail with ErrBadConn because query was successfully sent to server
if _, ok := err.(ServerError); !ok {
t.Error("processQueryResponse expected to fail with ServerError error but failed with other error: ", err)
}

if conn.connectionGood {
t.Fatal("Connection should be in a bad state")
}
}

func TestProcessQueryNextErrors(t *testing.T) {
tl := testLogger{t: t}
defer tl.StopLogging()
Expand Down
3 changes: 1 addition & 2 deletions token.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package mssql
import (
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -959,7 +958,7 @@ func (t tokenProcessor) nextToken() (tokenStruct, error) {
}
// we did not get cancellation confirmation, something is not
// right, this connection is not usable anymore
return nil, errors.New("did not get cancellation confirmation from the server")
return nil, ServerError{Error{Message: "did not get cancellation confirmation from the server"}}
}
}

Expand Down