Fix JSON marshal panic when dealing with NaN values

This commit is contained in:
Dan Sosedoff 2018-11-27 16:51:51 -06:00
parent 3850eedf07
commit 903a265676
3 changed files with 73 additions and 53 deletions

View File

@ -9,9 +9,9 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/sosedoff/pgweb/pkg/command"
"github.com/stretchr/testify/assert"
)
var (
@ -78,6 +78,9 @@ func onWindows() bool {
}
func setup() {
// No pretty JSON for testsm
command.Opts.DisablePrettyJson = true
out, err := exec.Command(
testCommands["createdb"],
"-U", serverUser,
@ -133,7 +136,7 @@ func teardown() {
}
}
func test_NewClientFromUrl(t *testing.T) {
func testNewClientFromUrl(t *testing.T) {
url := fmt.Sprintf("postgres://%s@%s:%s/%s?sslmode=disable", serverUser, serverHost, serverPort, serverDatabase)
client, err := NewFromUrl(url, nil)
@ -145,7 +148,7 @@ func test_NewClientFromUrl(t *testing.T) {
assert.Equal(t, url, client.ConnectionString)
}
func test_NewClientFromUrl2(t *testing.T) {
func testNewClientFromUrl2(t *testing.T) {
url := fmt.Sprintf("postgresql://%s@%s:%s/%s?sslmode=disable", serverUser, serverHost, serverPort, serverDatabase)
client, err := NewFromUrl(url, nil)
@ -157,7 +160,7 @@ func test_NewClientFromUrl2(t *testing.T) {
assert.Equal(t, url, client.ConnectionString)
}
func test_ClientIdleTime(t *testing.T) {
func testClientIdleTime(t *testing.T) {
examples := map[time.Time]bool{
time.Now(): false, // Current time
time.Now().Add(time.Minute * -30): false, // 30 minutes ago
@ -172,25 +175,25 @@ func test_ClientIdleTime(t *testing.T) {
}
}
func test_Test(t *testing.T) {
func testTest(t *testing.T) {
assert.Equal(t, nil, testClient.Test())
}
func test_Info(t *testing.T) {
func testInfo(t *testing.T) {
res, err := testClient.Info()
assert.Equal(t, nil, err)
assert.NotEqual(t, nil, res)
}
func test_Activity(t *testing.T) {
func testActivity(t *testing.T) {
res, err := testClient.Activity()
assert.Equal(t, nil, err)
assert.NotEqual(t, nil, res)
}
func test_Databases(t *testing.T) {
func testDatabases(t *testing.T) {
res, err := testClient.Databases()
assert.Equal(t, nil, err)
@ -198,7 +201,7 @@ func test_Databases(t *testing.T) {
assert.Contains(t, res, "postgres")
}
func test_Objects(t *testing.T) {
func testObjects(t *testing.T) {
res, err := testClient.Objects()
objects := ObjectsFromResult(res)
@ -244,7 +247,7 @@ func test_Objects(t *testing.T) {
}
}
func test_Table(t *testing.T) {
func testTable(t *testing.T) {
res, err := testClient.Table("books")
columns := []string{
@ -262,7 +265,7 @@ func test_Table(t *testing.T) {
assert.Equal(t, 4, len(res.Rows))
}
func test_TableRows(t *testing.T) {
func testTableRows(t *testing.T) {
res, err := testClient.TableRows("books", RowsOptions{})
assert.Equal(t, nil, err)
@ -270,7 +273,7 @@ func test_TableRows(t *testing.T) {
assert.Equal(t, 15, len(res.Rows))
}
func test_TableInfo(t *testing.T) {
func testTableInfo(t *testing.T) {
res, err := testClient.TableInfo("books")
assert.Equal(t, nil, err)
@ -278,7 +281,7 @@ func test_TableInfo(t *testing.T) {
assert.Equal(t, 1, len(res.Rows))
}
func test_EstimatedTableRowsCount(t *testing.T) {
func testEstimatedTableRowsCount(t *testing.T) {
var count int64 = 15
res, err := testClient.EstimatedTableRowsCount("books", RowsOptions{})
@ -287,7 +290,7 @@ func test_EstimatedTableRowsCount(t *testing.T) {
assert.Equal(t, []Row{Row{count}}, res.Rows)
}
func test_TableRowsCount(t *testing.T) {
func testTableRowsCount(t *testing.T) {
var count int64 = 15
res, err := testClient.TableRowsCount("books", RowsOptions{})
@ -296,7 +299,7 @@ func test_TableRowsCount(t *testing.T) {
assert.Equal(t, []Row{Row{count}}, res.Rows)
}
func test_TableRowsCountWithLargeTable(t *testing.T) {
func testTableRowsCountWithLargeTable(t *testing.T) {
var count int64 = 100010
testClient.db.MustExec(`create table large_table as select s from generate_Series(1,100010) s;`)
testClient.db.MustExec(`VACUUM large_table;`)
@ -307,7 +310,7 @@ func test_TableRowsCountWithLargeTable(t *testing.T) {
assert.Equal(t, []Row{Row{count}}, res.Rows)
}
func test_TableIndexes(t *testing.T) {
func testTableIndexes(t *testing.T) {
res, err := testClient.TableIndexes("books")
assert.Equal(t, nil, err)
@ -315,7 +318,7 @@ func test_TableIndexes(t *testing.T) {
assert.Equal(t, 2, len(res.Rows))
}
func test_TableConstraints(t *testing.T) {
func testTableConstraints(t *testing.T) {
res, err := testClient.TableConstraints("editions")
assert.Equal(t, nil, err)
@ -324,7 +327,7 @@ func test_TableConstraints(t *testing.T) {
assert.Equal(t, Row{"integrity", "CHECK (book_id IS NOT NULL AND edition IS NOT NULL)"}, res.Rows[1])
}
func test_Query(t *testing.T) {
func testQuery(t *testing.T) {
res, err := testClient.Query("SELECT * FROM books")
assert.Equal(t, nil, err)
@ -332,7 +335,7 @@ func test_Query(t *testing.T) {
assert.Equal(t, 15, len(res.Rows))
}
func test_QueryError(t *testing.T) {
func testQueryError(t *testing.T) {
res, err := testClient.Query("SELCT * FROM books")
assert.NotEqual(t, nil, err)
@ -340,7 +343,7 @@ func test_QueryError(t *testing.T) {
assert.Equal(t, true, res == nil)
}
func test_QueryInvalidTable(t *testing.T) {
func testQueryInvalidTable(t *testing.T) {
res, err := testClient.Query("SELECT * FROM books2")
assert.NotEqual(t, nil, err)
@ -348,7 +351,7 @@ func test_QueryInvalidTable(t *testing.T) {
assert.Equal(t, true, res == nil)
}
func test_TableRowsOrderEscape(t *testing.T) {
func testTableRowsOrderEscape(t *testing.T) {
rows, err := testClient.TableRows("dummies", RowsOptions{SortColumn: "isDummy"})
assert.Equal(t, nil, err)
assert.Equal(t, 2, len(rows.Rows))
@ -359,7 +362,14 @@ func test_TableRowsOrderEscape(t *testing.T) {
assert.Equal(t, true, rows == nil)
}
func test_ResultCsv(t *testing.T) {
func testResultJSON(t *testing.T) {
result, err := testClient.Query("SELECT 'NaN'::float AS value;")
assert.NoError(t, err)
assert.Equal(t, `[{"value":null}]`, string(result.JSON()))
}
func testResultCsv(t *testing.T) {
res, _ := testClient.Query("SELECT * FROM books ORDER BY id ASC LIMIT 1")
csv := res.CSV()
@ -368,7 +378,7 @@ func test_ResultCsv(t *testing.T) {
assert.Equal(t, expected, string(csv))
}
func test_History(t *testing.T) {
func testHistory(t *testing.T) {
_, err := testClient.Query("SELECT * FROM books WHERE id = 12345")
query := testClient.History[len(testClient.History)-1].Query
@ -376,7 +386,7 @@ func test_History(t *testing.T) {
assert.Equal(t, "SELECT * FROM books WHERE id = 12345", query)
}
func test_HistoryError(t *testing.T) {
func testHistoryError(t *testing.T) {
_, err := testClient.Query("SELECT * FROM books123")
query := testClient.History[len(testClient.History)-1].Query
@ -384,7 +394,7 @@ func test_HistoryError(t *testing.T) {
assert.NotEqual(t, "SELECT * FROM books123", query)
}
func test_HistoryUniqueness(t *testing.T) {
func testHistoryUniqueness(t *testing.T) {
url := fmt.Sprintf("postgres://%s@%s:%s/%s?sslmode=disable", serverUser, serverHost, serverPort, serverDatabase)
client, _ := NewFromUrl(url, nil)
@ -395,7 +405,7 @@ func test_HistoryUniqueness(t *testing.T) {
assert.Equal(t, "SELECT * FROM books WHERE id = 1", client.History[0].Query)
}
func test_ReadOnlyMode(t *testing.T) {
func testReadOnlyMode(t *testing.T) {
url := fmt.Sprintf("postgres://%s@%s:%s/%s?sslmode=disable", serverUser, serverHost, serverPort, serverDatabase)
client, _ := NewFromUrl(url, nil)
@ -419,31 +429,32 @@ func TestAll(t *testing.T) {
setup()
setupClient()
test_NewClientFromUrl(t)
test_ClientIdleTime(t)
test_Test(t)
test_Info(t)
test_Activity(t)
test_Databases(t)
test_Objects(t)
test_Table(t)
test_TableRows(t)
test_TableInfo(t)
test_EstimatedTableRowsCount(t)
test_TableRowsCount(t)
test_TableRowsCountWithLargeTable(t)
test_TableIndexes(t)
test_TableConstraints(t)
test_Query(t)
test_QueryError(t)
test_QueryInvalidTable(t)
test_TableRowsOrderEscape(t)
test_ResultCsv(t)
test_History(t)
test_HistoryUniqueness(t)
test_HistoryError(t)
test_ReadOnlyMode(t)
test_DumpExport(t)
testNewClientFromUrl(t)
testClientIdleTime(t)
testTest(t)
testInfo(t)
testActivity(t)
testDatabases(t)
testObjects(t)
testTable(t)
testTableRows(t)
testTableInfo(t)
testEstimatedTableRowsCount(t)
testTableRowsCount(t)
testTableRowsCountWithLargeTable(t)
testTableIndexes(t)
testTableConstraints(t)
testQuery(t)
testQueryError(t)
testQueryInvalidTable(t)
testTableRowsOrderEscape(t)
testResultJSON(t)
testResultCsv(t)
testHistory(t)
testHistoryUniqueness(t)
testHistoryError(t)
testReadOnlyMode(t)
testDumpExport(t)
teardownClient()
teardown()

View File

@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/assert"
)
func test_DumpExport(t *testing.T) {
func testDumpExport(t *testing.T) {
url := fmt.Sprintf("postgres://%s@%s:%s/%s?sslmode=disable", serverUser, serverHost, serverPort, serverDatabase)
savePath := "/tmp/dump.sql.gz"

View File

@ -5,6 +5,7 @@ import (
"encoding/csv"
"encoding/json"
"fmt"
"math"
"reflect"
"strconv"
"time"
@ -51,6 +52,14 @@ func (res *Result) PrepareBigints() {
}
case reflect.Float64:
val := col.(float64)
// json.Marshal panics when dealing with NaN/Inf values
// issue: https://github.com/golang/go/issues/25721
if math.IsNaN(val) {
res.Rows[i][j] = nil
break
}
if val < -999999999999999 || val > 999999999999999 {
res.Rows[i][j] = strconv.FormatFloat(val, 'e', -1, 64)
}