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

Ignore sql.ErrNoRows #645

Merged
merged 4 commits into from
Oct 15, 2019
Merged

Ignore sql.ErrNoRows #645

merged 4 commits into from
Oct 15, 2019

Conversation

vutung2311
Copy link
Contributor

There are some cases that gorm can return sql.ErrNoRows when using with postgres and ON CONFLICT DO NOTHING RETURNING *. I think we can safely ignore this error as we're ignoring gorm.ErrRecordNotFound

Also add second argument of redis command trace to understand more clearly about the trace.

@codecov-io
Copy link

codecov-io commented Oct 6, 2019

Codecov Report

Merging #645 into master will decrease coverage by 0.46%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master    #645      +/-   ##
=========================================
- Coverage   88.36%   87.9%   -0.47%     
=========================================
  Files         123     123              
  Lines        7900    7640     -260     
=========================================
- Hits         6981    6716     -265     
- Misses        798     821      +23     
+ Partials      121     103      -18
Impacted Files Coverage Δ
module/apmgorm/context.go 88.57% <100%> (ø) ⬆️
model/marshal_fastjson.go 77.1% <0%> (-5.58%) ⬇️
utils.go 82.69% <0%> (-1.18%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7b7289b...4f0ee11. Read the comment docs.

@axw
Copy link
Member

axw commented Oct 7, 2019

@vutung2311 thanks for the PR!

The Gorm change seems reasonable, but can you please add a minimal test that fails before the change?

The Redis change should be made separately, if at all - please remove that from this PR so we can focus on one change at a time. If we do make the Redis change, it should be made across all of the agents - so please open a discussion at https://discuss.elastic.co/c/apm first.

@vutung2311
Copy link
Contributor Author

@vutung2311 thanks for the PR!

The Gorm change seems reasonable, but can you please add a minimal test that fails before the change?

The Redis change should be made separately, if at all - please remove that from this PR so we can focus on one change at a time. If we do make the Redis change, it should be made across all of the agents - so please open a discussion at https://discuss.elastic.co/c/apm first.

Understood. I'm gonna work on it.

@vutung2311
Copy link
Contributor Author

I tried quite a few ways for sqlite3 but making that test to have sql.ErrNoRows was not possible for me. I modified the test to use Postgres. I hope that won't hurt anything.

@vutung2311 vutung2311 changed the title Ignore sql.ErrNoRows and add a bit more information for redis command Ignore sql.ErrNoRows Oct 12, 2019
@axw
Copy link
Member

axw commented Oct 14, 2019

I tried quite a few ways for sqlite3 but making that test to have sql.ErrNoRows was not possible for me. I modified the test to use Postgres. I hope that won't hurt anything.

@vutung2311 thanks for the updates. I'd like to keep running the test against sqlite3, so it can be run without starting up PostgreSQL. How about this?

func TestCaptureErrors(t *testing.T) {
        t.Run("sqlite3", func(t *testing.T) {
                db, err := apmgorm.Open("sqlite3", ":memory:")
                require.NoError(t, err)
                defer db.Close()
        })

        if os.Getenv("PGHOST") == "" {
                t.Logf("PGHOST not specified, skipping")
        } else {
                t.Run("postgres", func(t *testing.T) {
                        db, err := apmgorm.Open("postgres", "user=postgres password=hunter2 dbname=test_db sslmode=disable")
                        require.NoError(t, err)
                        defer db.Close()
                })
        }
}

func testCaptureErrors(t *testing.T, db *gorm.DB, f func(ctx context.Context, db *gorm.DB)) {
        db.SetLogger(nopLogger{})
        db.AutoMigrate(&Product{})
        require.NoError(t, db.Unscoped().Delete(&Product{}).Error)

        _, spans, errors := apmtest.WithTransaction(func(ctx context.Context) {
                db = apmgorm.WithContext(ctx, db)

                // gorm.ErrRecordNotFound should not cause an error
                db.Where("code=?", "L1212").First(&Product{})

                // The postgres dialect will use QueryRow when inserting, in order to fetch
                // the inserted row ID. By using "ON CONFLICT (id) DO NOTHING", no row will
                // be inserted, and QueryRow will return sql.ErrNoRows. This should not be
                // reported as an error.
                product := Product{
                        Model: gorm.Model{
                                ID: 1001,
                        },
                        Code:  "1001",
                        Price: 1001,
                }
                require.NoError(t, db.Create(&product).Error)
                db.Set("gorm:insert_option", "ON CONFLICT (id) DO NOTHING").Create(&product)

                // invalid SQL should
                db.Where("bananas").First(&Product{})
        })
        assert.Len(t, spans, 4)
        require.Len(t, errors, 1)
        assert.Regexp(t, `.*bananas.*`, errors[0].Exception.Message)
}

@vutung2311
Copy link
Contributor Author

vutung2311 commented Oct 14, 2019

I tried quite a few ways for sqlite3 but making that test to have sql.ErrNoRows was not possible for me. I modified the test to use Postgres. I hope that won't hurt anything.

@vutung2311 thanks for the updates. I'd like to keep running the test against sqlite3, so it can be run without starting up PostgreSQL. How about this?

func TestCaptureErrors(t *testing.T) {
        t.Run("sqlite3", func(t *testing.T) {
                db, err := apmgorm.Open("sqlite3", ":memory:")
                require.NoError(t, err)
                defer db.Close()
        })

        if os.Getenv("PGHOST") == "" {
                t.Logf("PGHOST not specified, skipping")
        } else {
                t.Run("postgres", func(t *testing.T) {
                        db, err := apmgorm.Open("postgres", "user=postgres password=hunter2 dbname=test_db sslmode=disable")
                        require.NoError(t, err)
                        defer db.Close()
                })
        }
}

func testCaptureErrors(t *testing.T, db *gorm.DB, f func(ctx context.Context, db *gorm.DB)) {
        db.SetLogger(nopLogger{})
        db.AutoMigrate(&Product{})
        require.NoError(t, db.Unscoped().Delete(&Product{}).Error)

        _, spans, errors := apmtest.WithTransaction(func(ctx context.Context) {
                db = apmgorm.WithContext(ctx, db)

                // gorm.ErrRecordNotFound should not cause an error
                db.Where("code=?", "L1212").First(&Product{})

                // The postgres dialect will use QueryRow when inserting, in order to fetch
                // the inserted row ID. By using "ON CONFLICT (id) DO NOTHING", no row will
                // be inserted, and QueryRow will return sql.ErrNoRows. This should not be
                // reported as an error.
                product := Product{
                        Model: gorm.Model{
                                ID: 1001,
                        },
                        Code:  "1001",
                        Price: 1001,
                }
                require.NoError(t, db.Create(&product).Error)
                db.Set("gorm:insert_option", "ON CONFLICT (id) DO NOTHING").Create(&product)

                // invalid SQL should
                db.Where("bananas").First(&Product{})
        })
        assert.Len(t, spans, 4)
        require.Len(t, errors, 1)
        assert.Regexp(t, `.*bananas.*`, errors[0].Exception.Message)
}

Thank you for your suggestion. I changed the file with few modifications to make sure that tests are independent of each others.

Copy link
Member

@axw axw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @vutung2311, looks good! Just a couple of minor issues left, then it should be good to merge.

module/apmgorm/apmgorm_test.go Outdated Show resolved Hide resolved
module/apmgorm/apmgorm_test.go Outdated Show resolved Hide resolved
@axw
Copy link
Member

axw commented Oct 15, 2019

jenkins, run the tests please

@axw axw merged commit 7e01e99 into elastic:master Oct 15, 2019
@axw
Copy link
Member

axw commented Oct 15, 2019

Thanks again for your contribution @vutung2311!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants