Merge remote-tracking branch 'influx/master' into mr-godoc

pull/7781/head
Mark Rushakoff 2017-01-04 13:27:36 -08:00
commit 6a94d200c8
20 changed files with 246 additions and 98 deletions

View File

@ -23,6 +23,7 @@ The stress tool `influx_stress` will be removed in a subsequent release. We reco
### Bugfixes
- [#7784](https://github.com/influxdata/influxdb/pull/7784): Fix broken error return on meta client's UpdateUser and DropContinuousQuery methods.
- [#7741](https://github.com/influxdata/influxdb/pull/7741): Fix string quoting and significantly improve performance of `influx_inspect export`.
- [#7698](https://github.com/influxdata/influxdb/pull/7698): CLI was caching db/rp for insert into statements.
- [#7659](https://github.com/influxdata/influxdb/issues/7659): Fix CLI import bug when using self-signed SSL certificates.
@ -36,6 +37,7 @@ The stress tool `influx_stress` will be removed in a subsequent release. We reco
- [#6527](https://github.com/influxdata/influxdb/issues/6527): 0.12.2 Influx CLI client PRECISION returns "Unknown precision....
- [#7740](https://github.com/influxdata/influxdb/issues/7740): Fix parse key panic when missing tag value @oiooj
- [#7563](https://github.com/influxdata/influxdb/issues/7563): RP should not allow `INF` or `0` as a shard duration.
- [#7585](https://github.com/influxdata/influxdb/pull/7585): Return Error instead of panic when decoding point values.
## v1.1.1 [2016-12-06]

View File

@ -201,7 +201,7 @@ If generating the protobuf code is failing for you, check each of the following:
Generated Go Templates
----------------------
The query engine requires optimizes data structures for each data type so
The query engine requires optimized data structures for each data type so
instead of writing each implementation several times we use templates. _Do not
change code that ends in a `.gen.go` extension!_ Instead you must edit the
`.gen.go.tmpl` file that was used to generate it.

View File

@ -340,7 +340,7 @@ func (p *Point) UnixNano() int64 {
}
// Fields returns the fields for the point.
func (p *Point) Fields() map[string]interface{} {
func (p *Point) Fields() (map[string]interface{}, error) {
return p.pt.Fields()
}

View File

@ -459,9 +459,13 @@ func TestClient_PointFields(t *testing.T) {
fields := map[string]interface{}{"idle": 10.1, "system": 50.9, "user": 39.0}
p, _ := NewPoint("cpu_usage", tags, fields)
if !reflect.DeepEqual(fields, p.Fields()) {
pfields, err := p.Fields()
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(fields, pfields) {
t.Errorf("Error, got %v, expected %v",
p.Fields(), fields)
pfields, fields)
}
}

View File

@ -2740,7 +2740,7 @@ func ParseDuration(s string) (time.Duration, error) {
}
// Split string into individual runes.
a := split(s)
a := []rune(s)
// Start with a zero duration.
var d time.Duration
@ -2915,14 +2915,6 @@ func IdentNeedsQuotes(ident string) bool {
return false
}
// split splits a string into a slice of runes.
func split(s string) (a []rune) {
for _, ch := range s {
a = append(a, ch)
}
return
}
// isDateString returns true if the string looks like a date-only time literal.
func isDateString(s string) bool { return dateStringRegexp.MatchString(s) }

View File

@ -60,7 +60,7 @@ type Point interface {
SetTags(tags Tags)
// Fields returns the fields for the point.
Fields() Fields
Fields() (Fields, error)
// Time return the timestamp for the point.
Time() time.Time
@ -77,9 +77,6 @@ type Point interface {
// Key returns the key (measurement joined with tags) of the point.
Key() []byte
Data() []byte
SetData(buf []byte)
// String returns a string representation of the point. If there is a
// timestamp associated with the point then it will be specified with the default
// precision of nanoseconds.
@ -153,13 +150,13 @@ type FieldIterator interface {
StringValue() string
// IntegerValue returns the integer value of the current field.
IntegerValue() int64
IntegerValue() (int64, error)
// BooleanValue returns the boolean value of the current field.
BooleanValue() bool
BooleanValue() (bool, error)
// FloatValue returns the float value of the current field.
FloatValue() float64
FloatValue() (float64, error)
// Delete deletes the current field.
Delete()
@ -195,9 +192,6 @@ type point struct {
// text encoding of timestamp
ts []byte
// binary encoded field data
data []byte
// cached version of parsed fields from data
cachedFields map[string]interface{}
@ -1257,7 +1251,11 @@ func NewPointFromBytes(b []byte) (Point, error) {
if err := p.UnmarshalBinary(b); err != nil {
return nil, err
}
if len(p.Fields()) == 0 {
fields, err := p.Fields()
if err != nil {
return nil, err
}
if len(fields) == 0 {
return nil, ErrPointMustHaveAField
}
return p, nil
@ -1273,14 +1271,6 @@ func MustNewPoint(name string, tags Tags, fields Fields, time time.Time) Point {
return pt
}
func (p *point) Data() []byte {
return p.data
}
func (p *point) SetData(b []byte) {
p.data = b
}
// Key returns the key (measurement joined with tags) of the point.
func (p *point) Key() []byte {
return p.key
@ -1393,12 +1383,16 @@ func (p *point) AddTag(key, value string) {
}
// Fields returns the fields for the point.
func (p *point) Fields() Fields {
func (p *point) Fields() (Fields, error) {
if p.cachedFields != nil {
return p.cachedFields
return p.cachedFields, nil
}
p.cachedFields = p.unmarshalBinary()
return p.cachedFields
cf, err := p.unmarshalBinary()
if err != nil {
return nil, err
}
p.cachedFields = cf
return p.cachedFields, nil
}
// SetPrecision will round a time to the specified precision.
@ -1532,7 +1526,7 @@ func (p *point) RoundedString(d time.Duration) string {
p.time.Round(d).UnixNano())
}
func (p *point) unmarshalBinary() Fields {
func (p *point) unmarshalBinary() (Fields, error) {
iter := p.FieldIterator()
fields := make(Fields, 8)
for iter.Next() {
@ -1541,16 +1535,28 @@ func (p *point) unmarshalBinary() Fields {
}
switch iter.Type() {
case Float:
fields[string(iter.FieldKey())] = iter.FloatValue()
v, err := iter.FloatValue()
if err != nil {
return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err)
}
fields[string(iter.FieldKey())] = v
case Integer:
fields[string(iter.FieldKey())] = iter.IntegerValue()
v, err := iter.IntegerValue()
if err != nil {
return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err)
}
fields[string(iter.FieldKey())] = v
case String:
fields[string(iter.FieldKey())] = iter.StringValue()
case Boolean:
fields[string(iter.FieldKey())] = iter.BooleanValue()
v, err := iter.BooleanValue()
if err != nil {
return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err)
}
fields[string(iter.FieldKey())] = v
}
}
return fields
return fields, nil
}
// HashID returns a non-cryptographic checksum of the point's key.
@ -1844,31 +1850,30 @@ func (p *point) StringValue() string {
}
// IntegerValue returns the integer value of the current field.
func (p *point) IntegerValue() int64 {
func (p *point) IntegerValue() (int64, error) {
n, err := parseIntBytes(p.it.valueBuf, 10, 64)
if err != nil {
panic(fmt.Sprintf("unable to parse integer value %q: %v", p.it.valueBuf, err))
return 0, fmt.Errorf("unable to parse integer value %q: %v", p.it.valueBuf, err)
}
return n
return n, nil
}
// BooleanValue returns the boolean value of the current field.
func (p *point) BooleanValue() bool {
func (p *point) BooleanValue() (bool, error) {
b, err := parseBoolBytes(p.it.valueBuf)
if err != nil {
panic(fmt.Sprintf("unable to parse bool value %q: %v", p.it.valueBuf, err))
return false, fmt.Errorf("unable to parse bool value %q: %v", p.it.valueBuf, err)
}
return b
return b, nil
}
// FloatValue returns the float value of the current field.
func (p *point) FloatValue() float64 {
func (p *point) FloatValue() (float64, error) {
f, err := parseFloatBytes(p.it.valueBuf, 64)
if err != nil {
// panic because that's what the non-iterator code does
panic(fmt.Sprintf("unable to parse floating point value %q: %v", p.it.valueBuf, err))
return 0, fmt.Errorf("unable to parse floating point value %q: %v", p.it.valueBuf, err)
}
return f
return f, nil
}
// Delete deletes the current field.

View File

@ -246,7 +246,11 @@ func test(t *testing.T, line string, point TestPoint) {
}
for name, value := range point.RawFields {
val := pts[0].Fields()[name]
fields, err := pts[0].Fields()
if err != nil {
t.Fatal(err)
}
val := fields[name]
expfval, ok := val.(float64)
if ok && math.IsNaN(expfval) {
@ -254,8 +258,9 @@ func test(t *testing.T, line string, point TestPoint) {
if ok && !math.IsNaN(gotfval) {
t.Errorf(`ParsePoints("%s") field '%s' mismatch. exp NaN`, line, name)
}
} else if !reflect.DeepEqual(pts[0].Fields()[name], value) {
t.Errorf(`ParsePoints("%s") field '%s' mismatch. got %[3]v (%[3]T), exp %[4]v (%[4]T)`, line, name, pts[0].Fields()[name], value)
}
if !reflect.DeepEqual(val, value) {
t.Errorf(`ParsePoints("%s") field '%s' mismatch. got %[3]v (%[3]T), exp %[4]v (%[4]T)`, line, name, val, value)
}
}
@ -477,7 +482,11 @@ func TestParsePointMaxInt64(t *testing.T) {
if err != nil {
t.Fatalf(`ParsePoints("%s") mismatch. got %v, exp nil`, `cpu,host=serverA,region=us-west value=9223372036854775807i`, err)
}
if exp, got := int64(9223372036854775807), p[0].Fields()["value"].(int64); exp != got {
fields, err := p[0].Fields()
if err != nil {
t.Fatal(err)
}
if exp, got := int64(9223372036854775807), fields["value"].(int64); exp != got {
t.Fatalf("ParsePoints Value mismatch. \nexp: %v\ngot: %v", exp, got)
}
@ -615,7 +624,11 @@ func TestParsePointFloatScientific(t *testing.T) {
t.Errorf(`ParsePoints("%s") mismatch. got %v, exp nil`, `cpu,host=serverA,region=us-west value=1.0e4`, err)
}
if pts[0].Fields()["value"] != 1e4 {
fields, err := pts[0].Fields()
if err != nil {
t.Fatal(err)
}
if fields["value"] != 1e4 {
t.Errorf(`ParsePoints("%s") mismatch. got %v, exp nil`, `cpu,host=serverA,region=us-west value=1e4`, err)
}
}
@ -631,7 +644,11 @@ func TestParsePointFloatScientificUpper(t *testing.T) {
t.Errorf(`ParsePoints("%s") mismatch. got %v, exp nil`, `cpu,host=serverA,region=us-west value=1.0E4`, err)
}
if pts[0].Fields()["value"] != 1e4 {
fields, err := pts[0].Fields()
if err != nil {
t.Fatal(err)
}
if fields["value"] != 1e4 {
t.Errorf(`ParsePoints("%s") mismatch. got %v, exp nil`, `cpu,host=serverA,region=us-west value=1E4`, err)
}
}
@ -696,11 +713,19 @@ func TestParsePointWhitespace(t *testing.T) {
t.Fatalf("[Example %d] got %v measurement, expected %v", i, got, exp)
}
if got, exp := len(pts[0].Fields()), len(expPoint.Fields()); got != exp {
fields, err := pts[0].Fields()
if err != nil {
t.Fatal(err)
}
eFields, err := expPoint.Fields()
if err != nil {
t.Fatal(err)
}
if got, exp := len(fields), len(eFields); got != exp {
t.Fatalf("[Example %d] got %d fields, expected %d", i, got, exp)
}
if got, exp := pts[0].Fields()["value"], expPoint.Fields()["value"]; got != exp {
if got, exp := fields["value"], eFields["value"]; got != exp {
t.Fatalf(`[Example %d] got %v for field "value", expected %v`, i, got, exp)
}
@ -1449,16 +1474,20 @@ func TestParsePointIntsFloats(t *testing.T) {
}
pt := pts[0]
if _, ok := pt.Fields()["int"].(int64); !ok {
t.Errorf("ParsePoint() int field mismatch: got %T, exp %T", pt.Fields()["int"], int64(10))
fields, err := pt.Fields()
if err != nil {
t.Fatal(err)
}
if _, ok := fields["int"].(int64); !ok {
t.Errorf("ParsePoint() int field mismatch: got %T, exp %T", fields["int"], int64(10))
}
if _, ok := pt.Fields()["float"].(float64); !ok {
t.Errorf("ParsePoint() float field mismatch: got %T, exp %T", pt.Fields()["float64"], float64(11.0))
if _, ok := fields["float"].(float64); !ok {
t.Errorf("ParsePoint() float field mismatch: got %T, exp %T", fields["float64"], float64(11.0))
}
if _, ok := pt.Fields()["float2"].(float64); !ok {
t.Errorf("ParsePoint() float field mismatch: got %T, exp %T", pt.Fields()["float64"], float64(12.1))
if _, ok := fields["float2"].(float64); !ok {
t.Errorf("ParsePoint() float field mismatch: got %T, exp %T", fields["float64"], float64(12.1))
}
}
@ -1730,7 +1759,11 @@ func TestNewPointUnhandledType(t *testing.T) {
t.Errorf("NewPoint().String() mismatch.\ngot %v\nexp %v", pt.String(), exp)
}
if exp := "1970-01-01 00:00:00 +0000 UTC"; pt.Fields()["value"] != exp {
fields, err := pt.Fields()
if err != nil {
t.Fatal(err)
}
if exp := "1970-01-01 00:00:00 +0000 UTC"; fields["value"] != exp {
t.Errorf("NewPoint().String() mismatch.\ngot %v\nexp %v", pt.String(), exp)
}
}
@ -1896,8 +1929,11 @@ cpu value=2 1`
t.Fatalf("failed to write points: %s", err.Error())
}
pointFields := points[0].Fields()
value, ok := pointFields["\"a"]
fields, err := points[0].Fields()
if err != nil {
t.Fatal(err)
}
value, ok := fields["\"a"]
if !ok {
t.Fatalf("expected to parse field '\"a'")
}
@ -2003,8 +2039,12 @@ func TestPoint_FieldIterator_Simple(t *testing.T) {
t.Fatalf("'42i' should be an Integer, got %v", fi.Type())
}
if fi.IntegerValue() != 42 {
t.Fatalf("'42i' should be 42, got %d", fi.IntegerValue())
iv, err := fi.IntegerValue()
if err != nil {
t.Fatal(err)
}
if exp, got := int64(42), iv; exp != got {
t.Fatalf("'42i' should be %d, got %d", exp, got)
}
if !fi.Next() {
@ -2015,8 +2055,12 @@ func TestPoint_FieldIterator_Simple(t *testing.T) {
t.Fatalf("'42' should be a Float, got %v", fi.Type())
}
if fi.FloatValue() != 42.0 {
t.Fatalf("'42' should be %f, got %f", 42.0, fi.FloatValue())
fv, err := fi.FloatValue()
if err != nil {
t.Fatal(err)
}
if exp, got := 42.0, fv; exp != got {
t.Fatalf("'42' should be %f, got %f", exp, got)
}
if fi.Next() {
@ -2028,20 +2072,24 @@ func toFields(fi models.FieldIterator) models.Fields {
m := make(models.Fields)
for fi.Next() {
var v interface{}
var err error
switch fi.Type() {
case models.Float:
v = fi.FloatValue()
v, err = fi.FloatValue()
case models.Integer:
v = fi.IntegerValue()
v, err = fi.IntegerValue()
case models.String:
v = fi.StringValue()
case models.Boolean:
v = fi.BooleanValue()
v, err = fi.BooleanValue()
case models.Empty:
v = nil
default:
panic("unknown type")
}
if err != nil {
panic(err)
}
m[string(fi.FieldKey())] = v
}
return m
@ -2064,7 +2112,10 @@ m a=2i,b=3i,c=true,d="stuff",e=-0.23,f=123.456
}
for _, p := range points {
exp := p.Fields()
exp, err := p.Fields()
if err != nil {
t.Fatal(err)
}
got := toFields(p.FieldIterator())
if !reflect.DeepEqual(got, exp) {

View File

@ -40,5 +40,8 @@ func (c Config) Validate() error {
if c.StoreInterval <= 0 {
return errors.New("monitor store interval must be positive")
}
if c.StoreDatabase == "" {
return errors.New("monitor store database name must not be empty")
}
return nil
}

View File

@ -28,3 +28,25 @@ store-interval="10m"
t.Fatalf("unexpected store-interval: %s", c.StoreInterval)
}
}
func TestConfig_Validate(t *testing.T) {
// NewConfig must validate correctly.
c := monitor.NewConfig()
if err := c.Validate(); err != nil {
t.Fatalf("unexpected validation error: %s", err)
}
// Non-positive duration is invalid.
c = monitor.NewConfig()
c.StoreInterval *= 0
if err := c.Validate(); err == nil {
t.Fatalf("unexpected successful validation for %#v", c)
}
// Empty database is invalid.
c = monitor.NewConfig()
c.StoreDatabase = ""
if err := c.Validate(); err == nil {
t.Fatalf("unexpected successful validation for %#v", c)
}
}

View File

@ -228,8 +228,12 @@ func TestParse(t *testing.T) {
if len(point.Tags()) != len(test.tags) {
t.Fatalf("tags len mismatch. expected %d, got %d", len(test.tags), len(point.Tags()))
}
f := point.Fields()["value"].(float64)
if point.Fields()["value"] != f {
fields, err := point.Fields()
if err != nil {
t.Fatal(err)
}
f := fields["value"].(float64)
if fields["value"] != f {
t.Fatalf("floatValue value mismatch. expected %v, got %v", test.value, f)
}
if point.Time().UnixNano()/1000000 != test.time.UnixNano()/1000000 {

View File

@ -442,7 +442,7 @@ func (c *Client) UpdateUser(name, password string) error {
}
if err := data.UpdateUser(name, string(hash)); err != nil {
return nil
return err
}
delete(c.authCache, name)
@ -869,7 +869,7 @@ func (c *Client) DropContinuousQuery(database, name string) error {
data := c.cacheData.Clone()
if err := data.DropContinuousQuery(database, name); err != nil {
return nil
return err
}
if err := c.commit(data); err != nil {

View File

@ -680,6 +680,19 @@ func TestMetaClient_CreateUser(t *testing.T) {
}
}
func TestMetaClient_UpdateUser(t *testing.T) {
t.Parallel()
d, c := newClient()
defer os.RemoveAll(d)
defer c.Close()
// UpdateUser that doesn't exist should return an error.
if err := c.UpdateUser("foo", "bar"); err == nil {
t.Fatalf("expected error, got nil")
}
}
func TestMetaClient_ContinuousQueries(t *testing.T) {
t.Parallel()
@ -729,6 +742,11 @@ func TestMetaClient_ContinuousQueries(t *testing.T) {
if err := c.DropContinuousQuery("db0", "cq1"); err != nil {
t.Fatal(err)
}
// Dropping a nonexistent CQ should return an error.
if err := c.DropContinuousQuery("db0", "not-a-cq"); err == nil {
t.Fatal("expected an error, got nil")
}
}
func TestMetaClient_Subscriptions_Create(t *testing.T) {

View File

@ -142,7 +142,11 @@ func getRandomFieldKey(m map[string]interface{}) string {
}
func setMapValues(m map[string]interface{}, p models.Point) {
m["%f"] = getRandomFieldKey(p.Fields())
fields, err := p.Fields()
if err != nil {
panic(err)
}
m["%f"] = getRandomFieldKey(fields)
m["%m"] = p.Name()
m["%t"] = getRandomTagPair(p.Tags())
m["%a"] = p.UnixNano()

View File

@ -15,8 +15,12 @@ func TestCommunePoint(t *testing.T) {
if point.Tags().GetString("tag") != "tagVal" {
t.Errorf("expected: tagVal\ngot: %v", point.Tags().GetString("tag"))
}
if int(point.Fields()["fooField"].(float64)) != 5 {
t.Errorf("expected: 5\ngot: %v\n", point.Fields()["fooField"])
fields, err := point.Fields()
if err != nil {
t.Fatal(err)
}
if int(fields["fooField"].(float64)) != 5 {
t.Errorf("expected: 5\ngot: %v\n", fields["fooField"])
}
// Make sure commune returns the prev point
comm.ch <- ""
@ -27,8 +31,8 @@ func TestCommunePoint(t *testing.T) {
if point.Tags().GetString("tag") != "tagVal" {
t.Errorf("expected: tagVal\ngot: %v", point.Tags().GetString("tag"))
}
if int(point.Fields()["fooField"].(float64)) != 5 {
t.Errorf("expected: 5\ngot: %v\n", point.Fields()["fooField"])
if int(fields["fooField"].(float64)) != 5 {
t.Errorf("expected: 5\ngot: %v\n", fields["fooField"])
}
}
@ -43,7 +47,11 @@ func TestSetCommune(t *testing.T) {
if pt.Tags().GetString("tag") != "tagVal" {
t.Errorf("expected: tagVal\ngot: %v", pt.Tags().GetString("tag"))
}
if int(pt.Fields()["fooField"].(float64)) != 5 {
t.Errorf("expected: 5\ngot: %v\n", pt.Fields()["fooField"])
fields, err := pt.Fields()
if err != nil {
t.Fatal(err)
}
if int(fields["fooField"].(float64)) != 5 {
t.Errorf("expected: 5\ngot: %v\n", fields["fooField"])
}
}

View File

@ -57,7 +57,11 @@ func TestWritePoint(t *testing.T) {
if statementID != got {
t.Errorf("expected: %v\ngot: %v\n", statementID, got)
}
got2 := int(pt.Fields()["status_code"].(int64))
fields, err := pt.Fields()
if err != nil {
t.Fatal(err)
}
got2 := int(fields["status_code"].(int64))
if responseCode != got2 {
t.Errorf("expected: %v\ngot: %v\n", responseCode, got2)
}
@ -80,7 +84,11 @@ func TestQueryPoint(t *testing.T) {
if statementID != got {
t.Errorf("expected: %v\ngot: %v\n", statementID, got)
}
got2 := int(pt.Fields()["status_code"].(int64))
fields, err := pt.Fields()
if err != nil {
t.Fatal(err)
}
got2 := int(fields["status_code"].(int64))
if responseCode != got2 {
t.Errorf("expected: %v\ngot: %v\n", responseCode, got2)
}

View File

@ -23,7 +23,7 @@ func NewResponse(pt *influx.Point, tr *Tracer) Response {
}
// AddTags adds additional tags to the point held in Response and returns the point
func (resp Response) AddTags(newTags map[string]string) *influx.Point {
func (resp Response) AddTags(newTags map[string]string) (*influx.Point, error) {
// Pull off the current tags
tags := resp.Point.Tags()
@ -34,12 +34,17 @@ func (resp Response) AddTags(newTags map[string]string) *influx.Point {
}
// Make a new point
pt, err := influx.NewPoint(resp.Point.Name(), tags, resp.Point.Fields(), resp.Point.Time())
fields, err := resp.Point.Fields()
if err != nil {
return nil, err
}
pt, err := influx.NewPoint(resp.Point.Name(), tags, fields, resp.Point.Time())
// panic on error
if err != nil {
log.Fatalf("Error adding tags to response point\n point: %v\n tags:%v\n error: %v\n", resp.Point, newTags, err)
}
return pt
return pt, nil
}

View File

@ -9,7 +9,10 @@ func TestNewResponse(t *testing.T) {
tr := NewTracer(map[string]string{})
r := NewResponse(pt, tr)
expected := "another_tag_value"
test := r.AddTags(map[string]string{"another_tag": "another_tag_value"})
test, err := r.AddTags(map[string]string{"another_tag": "another_tag_value"})
if err != nil {
t.Fatal(err)
}
got := test.Tags()["another_tag"]
if expected != got {
t.Errorf("expected: %v\ngot: %v\n", expected, got)

View File

@ -107,7 +107,10 @@ func (st *StressTest) resultsListen() {
resp.Tracer.Done()
default:
// Add the StressTest tags
pt := resp.AddTags(st.tags())
pt, err := resp.AddTags(st.tags())
if err != nil {
panic(err)
}
// Add the point to the batch
bp = st.batcher(pt, bp)
resp.Tracer.Done()

View File

@ -2146,7 +2146,11 @@ func assertEqual(t *testing.T, a tsm1.Value, b models.Point, field string) {
if got, exp := a.UnixNano(), b.UnixNano(); got != exp {
t.Fatalf("time mismatch: got %v, exp %v", got, exp)
}
if got, exp := a.Value(), b.Fields()[field]; got != exp {
fields, err := b.Fields()
if err != nil {
t.Fatal(err)
}
if got, exp := a.Value(), fields[field]; got != exp {
t.Fatalf("value mismatch: got %v, exp %v", got, exp)
}
}

View File

@ -681,13 +681,25 @@ func (e *Engine) WritePoints(points []models.Point) error {
var v Value
switch iter.Type() {
case models.Float:
v = NewFloatValue(t, iter.FloatValue())
fv, err := iter.FloatValue()
if err != nil {
return err
}
v = NewFloatValue(t, fv)
case models.Integer:
v = NewIntegerValue(t, iter.IntegerValue())
iv, err := iter.IntegerValue()
if err != nil {
return err
}
v = NewIntegerValue(t, iv)
case models.String:
v = NewStringValue(t, iter.StringValue())
case models.Boolean:
v = NewBooleanValue(t, iter.BooleanValue())
bv, err := iter.BooleanValue()
if err != nil {
return err
}
v = NewBooleanValue(t, bv)
default:
return fmt.Errorf("unknown field type for %s: %s", string(iter.FieldKey()), p.String())
}