You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
538 lines
15 KiB
538 lines
15 KiB
package hbaseutil |
|
|
|
import ( |
|
"encoding/binary" |
|
"encoding/json" |
|
"github.com/tsuna/gohbase/hrpc" |
|
"reflect" |
|
"testing" |
|
"time" |
|
) |
|
|
|
func uint64ToByte(value uint64) []byte { |
|
var buf = make([]byte, 8) |
|
binary.BigEndian.PutUint64(buf, value) |
|
return buf |
|
} |
|
|
|
func uint32ToByte(value uint32) []byte { |
|
var buf = make([]byte, 4) |
|
binary.BigEndian.PutUint32(buf, value) |
|
return buf |
|
} |
|
|
|
func uint16ToByte(value uint16) []byte { |
|
var buf = make([]byte, 2) |
|
binary.BigEndian.PutUint16(buf, value) |
|
return buf |
|
} |
|
|
|
type testStruct struct { |
|
A int64 `family:"f" qualifier:"q64"` |
|
B *int32 `family:"f" qualifier:"q32"` |
|
C int16 `family:"f" qualifier:"q16"` |
|
D int `qualifier:"q"` |
|
S *string `qualifier:"s"` |
|
FailField bool `family:"f" qualifier:"fail"` |
|
|
|
MapInt map[string]int `family:"m1"` |
|
MapString map[string]string `family:"m2"` |
|
} |
|
|
|
func (t *testStruct) equal(o testStruct) bool { |
|
return t.A == o.A && |
|
*t.B == *o.B && |
|
t.C == o.C && |
|
t.D == o.D && |
|
*t.S == *o.S && |
|
t.FailField == o.FailField && |
|
reflect.DeepEqual(t.MapInt, o.MapInt) && |
|
reflect.DeepEqual(t.MapString, o.MapString) |
|
|
|
} |
|
|
|
var testcase = [][]*hrpc.Cell{ |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("q64"), Value: uint64ToByte(10000000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q32"), Value: uint32ToByte(1000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q16"), Value: uint16ToByte(100)}, |
|
{Family: []byte("f"), Qualifier: []byte("q"), Value: uint64ToByte(1000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("s"), Value: []byte("just test")}, |
|
{Family: []byte("f"), Qualifier: []byte("fail"), Value: []byte("1")}, |
|
{Family: []byte("m1"), Qualifier: []byte("k1"), Value: uint32ToByte(1)}, |
|
{Family: []byte("m1"), Qualifier: []byte("k2"), Value: uint16ToByte(2)}, |
|
{Family: []byte("m2"), Qualifier: []byte("k1"), Value: []byte("1")}, |
|
{Family: []byte("m2"), Qualifier: []byte("k2"), Value: []byte("2")}, |
|
}, |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("q64"), Value: uint64ToByte(10000000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q32"), Value: uint64ToByte(10000000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q16"), Value: uint64ToByte(10000000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q"), Value: uint64ToByte(10000000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("s"), Value: []byte("just test2")}, |
|
{Family: []byte("f"), Qualifier: []byte("fail"), Value: []byte("1")}, |
|
}, |
|
} |
|
var resultb = []int32{ |
|
1000000, |
|
10000000000 & 0xffffffff, |
|
} |
|
var results = []string{ |
|
"just test", |
|
"just test2", |
|
} |
|
var resultcase = []testStruct{ |
|
{A: 10000000000, B: &resultb[0], C: 100, D: 1000000, S: &results[0], |
|
MapInt: map[string]int{"k1": 1, "k2": 2}, |
|
MapString: map[string]string{"k1": "1", "k2": "2"}}, |
|
{A: 10000000000, B: &resultb[1], C: -7168, D: int(10000000000), S: &results[1]}, |
|
} |
|
|
|
func TestParser_Parse(t *testing.T) { |
|
var parser = Parser{} |
|
|
|
for i, cells := range testcase { |
|
var result testStruct |
|
var err = parser.Parse(cells, &result) |
|
if err != nil { |
|
t.Logf("err=%v", err) |
|
t.Fail() |
|
} |
|
t.Logf("result=%v, expect=%v", result, resultcase[i]) |
|
if !resultcase[i].equal(result) { |
|
t.Logf("fail case: index=%d", i) |
|
t.Fail() |
|
} |
|
|
|
} |
|
} |
|
|
|
var testcase2 = [][]*hrpc.Cell{ |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("q64"), Value: []byte("10000000000")}, |
|
{Family: []byte("f"), Qualifier: []byte("q32"), Value: []byte("1000000")}, |
|
{Family: []byte("f"), Qualifier: []byte("q16"), Value: []byte("100")}, |
|
{Family: []byte("f"), Qualifier: []byte("q"), Value: []byte("1000000")}, |
|
{Family: []byte("f"), Qualifier: []byte("s"), Value: []byte("just test")}, |
|
{Family: []byte("f"), Qualifier: []byte("fail"), Value: []byte("1")}, |
|
{Family: []byte("m1"), Qualifier: []byte("k1"), Value: []byte("1")}, |
|
{Family: []byte("m1"), Qualifier: []byte("k2"), Value: []byte("2")}, |
|
{Family: []byte("m2"), Qualifier: []byte("k1"), Value: []byte("1")}, |
|
{Family: []byte("m2"), Qualifier: []byte("k2"), Value: []byte("2")}, |
|
}, |
|
} |
|
var resultcase2 = []testStruct{ |
|
{A: 10000000000, B: &resultb[0], C: 100, D: 1000000, S: &results[0], |
|
MapInt: map[string]int{"k1": 1, "k2": 2}, |
|
MapString: map[string]string{"k1": "1", "k2": "2"}}, |
|
} |
|
|
|
func TestParser_ParseCustomParseInt(t *testing.T) { |
|
var parser = Parser{ |
|
ParseIntFunc: StringToUint, |
|
} |
|
|
|
for i, cells := range testcase2 { |
|
var result testStruct |
|
var err = parser.Parse(cells, &result) |
|
if err != nil { |
|
t.Logf("err=%v", err) |
|
t.Fail() |
|
} |
|
t.Logf("result=%v, expect=%v", result, resultcase[i]) |
|
if !resultcase2[i].equal(result) { |
|
t.Logf("fail case: index=%d", i) |
|
t.Fail() |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
func TestParser_StringInt(t *testing.T) { |
|
var testcase2 = [][]*hrpc.Cell{ |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("q64"), Value: []byte("9223372036854775807")}, |
|
{Family: []byte("f"), Qualifier: []byte("q32"), Value: []byte("1000000")}, |
|
{Family: []byte("f"), Qualifier: []byte("q16"), Value: []byte("10000")}, |
|
{Family: []byte("f"), Qualifier: []byte("q"), Value: []byte("100")}, |
|
}, |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("q64"), Value: []byte("-9223372036854775808")}, |
|
{Family: []byte("f"), Qualifier: []byte("q32"), Value: []byte("-2")}, |
|
{Family: []byte("f"), Qualifier: []byte("q16"), Value: []byte("-3")}, |
|
{Family: []byte("f"), Qualifier: []byte("q"), Value: []byte("-4")}, |
|
{Family: []byte("f"), Qualifier: []byte("u64"), Value: []byte("18446744073709551615")}, |
|
{Family: []byte("f"), Qualifier: []byte("u32"), Value: []byte("2147483648")}, |
|
{Family: []byte("f"), Qualifier: []byte("u16"), Value: []byte("32768")}, |
|
{Family: []byte("f"), Qualifier: []byte("u8"), Value: []byte("128")}, |
|
}, |
|
} |
|
type testStruct struct { |
|
A int64 `family:"f" qualifier:"q64"` |
|
B int32 `family:"f" qualifier:"q32"` |
|
C int16 `family:"f" qualifier:"q16"` |
|
D int8 `qualifier:"q"` |
|
U64 uint64 `family:"f" qualifier:"u64"` |
|
U32 uint32 `family:"f" qualifier:"u32"` |
|
U16 uint16 `family:"f" qualifier:"u16"` |
|
U8 uint8 `family:"f" qualifier:"u8"` |
|
} |
|
var expect = []testStruct{ |
|
{ |
|
A: 9223372036854775807, B: 1000000, C: 10000, D: 100, |
|
}, |
|
{ |
|
A: -9223372036854775808, B: -2, C: -3, D: -4, |
|
U64: 18446744073709551615, U32: 2147483648, U16: 32768, U8: 128, |
|
}, |
|
} |
|
var parser = Parser{ |
|
ParseIntFunc: StringToUint, |
|
} |
|
|
|
for i, cells := range testcase2 { |
|
var result testStruct |
|
var err = parser.Parse(cells, &result) |
|
if err != nil { |
|
t.Logf("err=%v", err) |
|
t.Fail() |
|
} |
|
t.Logf("result=%+v, expect=%+v", result, expect[i]) |
|
if !reflect.DeepEqual(expect[i], result) { |
|
t.Logf("fail case: index=%d", i) |
|
t.Fail() |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
func TestParser_InterfaceInterface(t *testing.T) { |
|
var parser = Parser{} |
|
|
|
for i, cells := range testcase { |
|
var st testStruct |
|
var result interface{} = &st |
|
var err = parser.Parse(cells, result) |
|
if err != nil { |
|
t.Logf("err=%v", err) |
|
t.Fail() |
|
} |
|
t.Logf("result=%v, expect=%v", result, resultcase[i]) |
|
if !resultcase[i].equal(*result.(*testStruct)) { |
|
t.Logf("fail case: index=%d", i) |
|
t.Fail() |
|
} |
|
|
|
} |
|
} |
|
|
|
type testOnlyQualifier struct { |
|
A int64 `qualifier:"q64"` |
|
B *int32 `qualifier:"q32"` |
|
C int16 `qualifier:"q16"` |
|
D int `qualifier:"q"` |
|
S *string `qualifier:"s"` |
|
FailField bool `qualifier:"fail"` |
|
MapInt map[string]int `family:"m1"` |
|
MapString map[string]string `family:"m2"` |
|
} |
|
|
|
var testcase3 = [][]*hrpc.Cell{ |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("q64"), Value: uint64ToByte(10000000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q32"), Value: uint32ToByte(1000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q16"), Value: uint16ToByte(100)}, |
|
{Family: []byte("f"), Qualifier: []byte("q"), Value: uint64ToByte(1000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("s"), Value: []byte("just test")}, |
|
{Family: []byte("f"), Qualifier: []byte("fail"), Value: []byte("1")}, |
|
{Family: []byte("m1"), Qualifier: []byte("k1"), Value: uint32ToByte(1)}, |
|
{Family: []byte("m1"), Qualifier: []byte("k2"), Value: uint16ToByte(2)}, |
|
{Family: []byte("m2"), Qualifier: []byte("k1"), Value: []byte("1")}, |
|
{Family: []byte("m2"), Qualifier: []byte("k2"), Value: []byte("2")}, |
|
}, |
|
} |
|
|
|
var resultcase3 = []testOnlyQualifier{ |
|
{A: 10000000000, B: &resultb[0], C: 100, D: 1000000, S: &results[0], |
|
MapInt: map[string]int{"k1": 1, "k2": 2}, |
|
MapString: map[string]string{"k1": "1", "k2": "2"}}, |
|
} |
|
|
|
func (t *testOnlyQualifier) equal(o testOnlyQualifier) bool { |
|
return t.A == o.A && |
|
*t.B == *o.B && |
|
t.C == o.C && |
|
t.D == o.D && |
|
*t.S == *o.S && |
|
t.FailField == o.FailField && |
|
reflect.DeepEqual(t.MapInt, o.MapInt) && |
|
reflect.DeepEqual(t.MapString, o.MapString) |
|
|
|
} |
|
func TestParser_OnlyQualifier(t *testing.T) { |
|
var parser = Parser{} |
|
|
|
for i, cells := range testcase3 { |
|
var result testOnlyQualifier |
|
var err = parser.Parse(cells, &result) |
|
if err != nil { |
|
t.Logf("err=%v", err) |
|
t.Fail() |
|
} |
|
t.Logf("result=%v, expect=%v", result, resultcase3[i]) |
|
if !resultcase3[i].equal(result) { |
|
t.Logf("fail case: index=%d", i) |
|
t.Fail() |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
func TestParser_PartialFamilyPartPartialQualifier(t *testing.T) { |
|
var testcase = [][]*hrpc.Cell{ |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("q64"), Value: uint64ToByte(10000000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q32"), Value: uint32ToByte(1000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q16"), Value: uint16ToByte(100)}, |
|
{Family: []byte("f"), Qualifier: []byte("q"), Value: uint64ToByte(1000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("s"), Value: []byte("just test")}, |
|
{Family: []byte("f"), Qualifier: []byte("fail"), Value: []byte("1")}, |
|
}, |
|
} |
|
|
|
type testStruct struct { |
|
A int `family:"f" qualifier:"q64"` |
|
Map map[string]int `family:"f"` |
|
} |
|
var resultcase = []testStruct{ |
|
{A: 10000000000, |
|
Map: map[string]int{ |
|
"q32": 1000000, |
|
"q16": 100, |
|
"q": 1000000, |
|
"fail": int('1'), |
|
}}, |
|
} |
|
|
|
var parser = Parser{} |
|
|
|
for i, cells := range testcase { |
|
|
|
var result testStruct |
|
var resInterface interface{} = &result |
|
var start = time.Now() |
|
var err = parser.Parse(cells, &resInterface) |
|
var elapse = time.Since(start) |
|
if err != nil { |
|
t.Logf("err=%v", err) |
|
t.Fail() |
|
} |
|
t.Logf("result=%v, expect=%v, parse time=%v", resInterface, resultcase[i], elapse) |
|
if !reflect.DeepEqual(resultcase[i], result) { |
|
t.Logf("fail case: index=%d", i) |
|
t.Fail() |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
func TestParser_SetBasicValue(t *testing.T) { |
|
var ( |
|
i32s int32 = -2 |
|
i64s int64 = -3 |
|
i16s int16 = -4 |
|
|
|
i32d int32 |
|
i64d int64 |
|
i16d int16 |
|
|
|
i64Bytes = uint64ToByte(uint64(i64s)) |
|
i32Bytes = uint32ToByte(uint32(i32s)) |
|
i16Bytes = uint16ToByte(uint16(i16s)) |
|
) |
|
|
|
var rvi32 = reflect.ValueOf(&i32d) |
|
var e = setBasicValue(i32Bytes, rvi32, "rvi32", ByteBigEndianToUint64) |
|
if e != nil { |
|
t.Errorf("fail, err=%+v", e) |
|
t.FailNow() |
|
} |
|
if i32s != i32d { |
|
t.Errorf("fail,expect=%d, got=%d", i32d, i32s) |
|
t.FailNow() |
|
} |
|
|
|
var rvi64 = reflect.ValueOf(&i64d) |
|
e = setBasicValue(i64Bytes, rvi64, "rvi64", ByteBigEndianToUint64) |
|
if e != nil { |
|
t.Errorf("fail, err=%+v", e) |
|
t.FailNow() |
|
} |
|
if i64s != i64d { |
|
t.Errorf("fail,expect=%d, got=%d", i64d, i64s) |
|
t.FailNow() |
|
} |
|
var rvi16 = reflect.ValueOf(&i16d) |
|
e = setBasicValue(i16Bytes, rvi16, "rvi16", ByteBigEndianToUint64) |
|
if e != nil { |
|
t.Errorf("fail, err=%+v", e) |
|
t.FailNow() |
|
} |
|
if i16s != i16d { |
|
t.Errorf("fail,expect=%d, got=%d", i16d, i16s) |
|
t.FailNow() |
|
} |
|
|
|
} |
|
|
|
func TestParser_Minus(t *testing.T) { |
|
var i64 int64 = -2 |
|
var i32 int32 = -3 |
|
var i16 int16 = -4 |
|
var i8 int8 = -128 |
|
var testcase = [][]*hrpc.Cell{ |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("i64"), Value: uint64ToByte(uint64(i64))}, |
|
{Family: []byte("f"), Qualifier: []byte("i32"), Value: uint32ToByte(uint32(i32))}, |
|
{Family: []byte("f"), Qualifier: []byte("i16"), Value: uint16ToByte(uint16(i16))}, |
|
{Family: []byte("f"), Qualifier: []byte("i8"), Value: []byte{uint8(i8)}}, |
|
}, |
|
} |
|
|
|
type testStruct struct { |
|
I64 int64 `family:"f" qualifier:"i64"` |
|
I32 int32 `family:"f" qualifier:"i32"` |
|
I16 int16 `family:"f" qualifier:"i16"` |
|
I8 int8 `family:"f" qualifier:"i8"` |
|
} |
|
|
|
var resultcase = []testStruct{ |
|
{ |
|
I64: i64, |
|
I32: i32, |
|
I16: i16, |
|
I8: i8, |
|
}, |
|
} |
|
|
|
var parser = Parser{} |
|
|
|
for i, cells := range testcase { |
|
|
|
var result testStruct |
|
var resInterface interface{} = &result |
|
var start = time.Now() |
|
var err = parser.Parse(cells, &resInterface) |
|
var elapse = time.Since(start) |
|
if err != nil { |
|
t.Logf("err=%v", err) |
|
t.Fail() |
|
} |
|
t.Logf("result=%v, expect=%v, parse time=%v", resInterface, resultcase[i], elapse) |
|
if !reflect.DeepEqual(resultcase[i], result) { |
|
t.Logf("fail case: index=%d", i) |
|
t.Fail() |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
func TestParser_Overflow(t *testing.T) { |
|
var testcase = [][]*hrpc.Cell{ |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("i64"), Value: uint64ToByte(0xff01020304050607)}, |
|
{Family: []byte("f"), Qualifier: []byte("i32"), Value: uint64ToByte(0xff01020304050607)}, |
|
{Family: []byte("f"), Qualifier: []byte("i16"), Value: uint64ToByte(0xff01020304050607)}, |
|
{Family: []byte("f"), Qualifier: []byte("i8"), Value: uint64ToByte(0xff01020304050607)}, |
|
}, |
|
} |
|
|
|
type testStruct struct { |
|
I64 int64 `family:"f" qualifier:"i64"` |
|
I32 int32 `family:"f" qualifier:"i32"` |
|
I16 int16 `family:"f" qualifier:"i16"` |
|
I8 int8 `family:"f" qualifier:"i8"` |
|
} |
|
|
|
var resultcase = []testStruct{ |
|
{ |
|
I64: -(0xffffffffffffffff - 0xff01020304050607 + 1), |
|
I32: 0xff01020304050607 & 0xffffffff, |
|
I16: 0xff01020304050607 & 0xffff, |
|
I8: 0xff01020304050607 & 0xff, |
|
}, |
|
} |
|
|
|
var parser = Parser{} |
|
|
|
for i, cells := range testcase { |
|
|
|
var result testStruct |
|
var resInterface interface{} = &result |
|
var start = time.Now() |
|
var err = parser.Parse(cells, &resInterface) |
|
var elapse = time.Since(start) |
|
if err != nil { |
|
t.Logf("err=%v", err) |
|
t.Fail() |
|
} |
|
t.Logf("result=%v, expect=%v, parse time=%v", resInterface, resultcase[i], elapse) |
|
if !reflect.DeepEqual(resultcase[i], result) { |
|
t.Logf("fail case: index=%d", i) |
|
t.Fail() |
|
} |
|
|
|
} |
|
} |
|
|
|
func BenchmarkParser(b *testing.B) { |
|
var testcase = [][]*hrpc.Cell{ |
|
{ |
|
{Family: []byte("f"), Qualifier: []byte("q64"), Value: uint64ToByte(10000000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q32"), Value: uint32ToByte(1000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("q16"), Value: uint16ToByte(100)}, |
|
{Family: []byte("f"), Qualifier: []byte("q"), Value: uint64ToByte(1000000)}, |
|
{Family: []byte("f"), Qualifier: []byte("fail"), Value: uint64ToByte(100)}, |
|
}, |
|
} |
|
|
|
type testStruct struct { |
|
A int `family:"f" qualifier:"q64"` |
|
B int32 `family:"f" qualifier:"q32"` |
|
C int16 `family:"f" qualifier:"q16"` |
|
D int `qualifier:"q"` |
|
S string `qualifier:"s"` |
|
Map map[string]int `family:"f"` |
|
} |
|
var parser Parser |
|
b.Logf("bench parser") |
|
for i := 0; i < b.N; i++ { |
|
var result testStruct |
|
parser.Parse(testcase[0], &result) |
|
} |
|
} |
|
|
|
func BenchmarkJson(b *testing.B) { |
|
var text = []byte("{\"a\": 123, \"b\": \"1234\", \"c\": \"1234\", \"d\": \"1234\", \"e\" :{\"a\": 123, \"b\": \"1234\"}}") |
|
var result struct { |
|
A int `json:"a"` |
|
B string `json:"b"` |
|
C string `json:"c"` |
|
D string `json:"d"` |
|
E struct { |
|
A int `json:"a"` |
|
B string `json:"b"` |
|
} `json:"e"` |
|
} |
|
b.Logf("bench json") |
|
for i := 0; i < b.N; i++ { |
|
if err := json.Unmarshal(text, &result); err != nil { |
|
b.FailNow() |
|
} |
|
} |
|
}
|
|
|