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.
 
 
 

386 lines
9.6 KiB

  1. // Copyright 2016 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package bigquery
  15. import (
  16. "context"
  17. "errors"
  18. "math"
  19. "math/big"
  20. "reflect"
  21. "testing"
  22. "time"
  23. "cloud.google.com/go/civil"
  24. "cloud.google.com/go/internal/testutil"
  25. "github.com/google/go-cmp/cmp"
  26. bq "google.golang.org/api/bigquery/v2"
  27. )
  28. var scalarTests = []struct {
  29. val interface{} // The Go value
  30. wantVal string // paramValue's desired output
  31. wantType *bq.QueryParameterType // paramType's desired output
  32. }{
  33. {int64(0), "0", int64ParamType},
  34. {3.14, "3.14", float64ParamType},
  35. {3.14159e-87, "3.14159e-87", float64ParamType},
  36. {true, "true", boolParamType},
  37. {"string", "string", stringParamType},
  38. {"\u65e5\u672c\u8a9e\n", "\u65e5\u672c\u8a9e\n", stringParamType},
  39. {math.NaN(), "NaN", float64ParamType},
  40. {[]byte("foo"), "Zm9v", bytesParamType}, // base64 encoding of "foo"
  41. {time.Date(2016, 3, 20, 4, 22, 9, 5000, time.FixedZone("neg1-2", -3720)),
  42. "2016-03-20 04:22:09.000005-01:02",
  43. timestampParamType},
  44. {civil.Date{Year: 2016, Month: 3, Day: 20}, "2016-03-20", dateParamType},
  45. {civil.Time{Hour: 4, Minute: 5, Second: 6, Nanosecond: 789000000}, "04:05:06.789000", timeParamType},
  46. {civil.DateTime{Date: civil.Date{Year: 2016, Month: 3, Day: 20}, Time: civil.Time{Hour: 4, Minute: 5, Second: 6, Nanosecond: 789000000}},
  47. "2016-03-20 04:05:06.789000",
  48. dateTimeParamType},
  49. {big.NewRat(12345, 1000), "12.345000000", numericParamType},
  50. }
  51. type (
  52. S1 struct {
  53. A int
  54. B *S2
  55. C bool
  56. }
  57. S2 struct {
  58. D string
  59. }
  60. )
  61. var (
  62. s1 = S1{
  63. A: 1,
  64. B: &S2{D: "s"},
  65. C: true,
  66. }
  67. s1ParamType = &bq.QueryParameterType{
  68. Type: "STRUCT",
  69. StructTypes: []*bq.QueryParameterTypeStructTypes{
  70. {Name: "A", Type: int64ParamType},
  71. {Name: "B", Type: &bq.QueryParameterType{
  72. Type: "STRUCT",
  73. StructTypes: []*bq.QueryParameterTypeStructTypes{
  74. {Name: "D", Type: stringParamType},
  75. },
  76. }},
  77. {Name: "C", Type: boolParamType},
  78. },
  79. }
  80. s1ParamValue = bq.QueryParameterValue{
  81. StructValues: map[string]bq.QueryParameterValue{
  82. "A": sval("1"),
  83. "B": {
  84. StructValues: map[string]bq.QueryParameterValue{
  85. "D": sval("s"),
  86. },
  87. },
  88. "C": sval("true"),
  89. },
  90. }
  91. s1ParamReturnValue = map[string]interface{}{
  92. "A": int64(1),
  93. "B": map[string]interface{}{"D": "s"},
  94. "C": true,
  95. }
  96. )
  97. func sval(s string) bq.QueryParameterValue {
  98. return bq.QueryParameterValue{Value: s}
  99. }
  100. func TestParamValueScalar(t *testing.T) {
  101. for _, test := range scalarTests {
  102. got, err := paramValue(reflect.ValueOf(test.val))
  103. if err != nil {
  104. t.Errorf("%v: got %v, want nil", test.val, err)
  105. continue
  106. }
  107. want := sval(test.wantVal)
  108. if !testutil.Equal(got, want) {
  109. t.Errorf("%v:\ngot %+v\nwant %+v", test.val, got, want)
  110. }
  111. }
  112. }
  113. func TestParamValueArray(t *testing.T) {
  114. qpv := bq.QueryParameterValue{ArrayValues: []*bq.QueryParameterValue{
  115. {Value: "1"},
  116. {Value: "2"},
  117. },
  118. }
  119. for _, test := range []struct {
  120. val interface{}
  121. want bq.QueryParameterValue
  122. }{
  123. {[]int(nil), bq.QueryParameterValue{}},
  124. {[]int{}, bq.QueryParameterValue{}},
  125. {[]int{1, 2}, qpv},
  126. {[2]int{1, 2}, qpv},
  127. } {
  128. got, err := paramValue(reflect.ValueOf(test.val))
  129. if err != nil {
  130. t.Fatal(err)
  131. }
  132. if !testutil.Equal(got, test.want) {
  133. t.Errorf("%#v:\ngot %+v\nwant %+v", test.val, got, test.want)
  134. }
  135. }
  136. }
  137. func TestParamValueStruct(t *testing.T) {
  138. got, err := paramValue(reflect.ValueOf(s1))
  139. if err != nil {
  140. t.Fatal(err)
  141. }
  142. if !testutil.Equal(got, s1ParamValue) {
  143. t.Errorf("got %+v\nwant %+v", got, s1ParamValue)
  144. }
  145. }
  146. func TestParamValueErrors(t *testing.T) {
  147. // paramValue lets a few invalid types through, but paramType catches them.
  148. // Since we never call one without the other that's fine.
  149. for _, val := range []interface{}{nil, new([]int)} {
  150. _, err := paramValue(reflect.ValueOf(val))
  151. if err == nil {
  152. t.Errorf("%v (%T): got nil, want error", val, val)
  153. }
  154. }
  155. }
  156. func TestParamType(t *testing.T) {
  157. for _, test := range scalarTests {
  158. got, err := paramType(reflect.TypeOf(test.val))
  159. if err != nil {
  160. t.Fatal(err)
  161. }
  162. if !testutil.Equal(got, test.wantType) {
  163. t.Errorf("%v (%T): got %v, want %v", test.val, test.val, got, test.wantType)
  164. }
  165. }
  166. for _, test := range []struct {
  167. val interface{}
  168. want *bq.QueryParameterType
  169. }{
  170. {uint32(32767), int64ParamType},
  171. {[]byte("foo"), bytesParamType},
  172. {[]int{}, &bq.QueryParameterType{Type: "ARRAY", ArrayType: int64ParamType}},
  173. {[3]bool{}, &bq.QueryParameterType{Type: "ARRAY", ArrayType: boolParamType}},
  174. {S1{}, s1ParamType},
  175. } {
  176. got, err := paramType(reflect.TypeOf(test.val))
  177. if err != nil {
  178. t.Fatal(err)
  179. }
  180. if !testutil.Equal(got, test.want) {
  181. t.Errorf("%v (%T): got %v, want %v", test.val, test.val, got, test.want)
  182. }
  183. }
  184. }
  185. func TestParamTypeErrors(t *testing.T) {
  186. for _, val := range []interface{}{
  187. nil, uint(0), new([]int), make(chan int),
  188. } {
  189. _, err := paramType(reflect.TypeOf(val))
  190. if err == nil {
  191. t.Errorf("%v (%T): got nil, want error", val, val)
  192. }
  193. }
  194. }
  195. func TestConvertParamValue(t *testing.T) {
  196. // Scalars.
  197. for _, test := range scalarTests {
  198. pval, err := paramValue(reflect.ValueOf(test.val))
  199. if err != nil {
  200. t.Fatal(err)
  201. }
  202. ptype, err := paramType(reflect.TypeOf(test.val))
  203. if err != nil {
  204. t.Fatal(err)
  205. }
  206. got, err := convertParamValue(&pval, ptype)
  207. if err != nil {
  208. t.Fatalf("convertParamValue(%+v, %+v): %v", pval, ptype, err)
  209. }
  210. if !testutil.Equal(got, test.val) {
  211. t.Errorf("%#v: got %#v", test.val, got)
  212. }
  213. }
  214. // Arrays.
  215. for _, test := range []struct {
  216. pval *bq.QueryParameterValue
  217. want []interface{}
  218. }{
  219. {
  220. &bq.QueryParameterValue{},
  221. nil,
  222. },
  223. {
  224. &bq.QueryParameterValue{
  225. ArrayValues: []*bq.QueryParameterValue{{Value: "1"}, {Value: "2"}},
  226. },
  227. []interface{}{int64(1), int64(2)},
  228. },
  229. } {
  230. ptype := &bq.QueryParameterType{Type: "ARRAY", ArrayType: int64ParamType}
  231. got, err := convertParamValue(test.pval, ptype)
  232. if err != nil {
  233. t.Fatalf("%+v: %v", test.pval, err)
  234. }
  235. if !testutil.Equal(got, test.want) {
  236. t.Errorf("%+v: got %+v, want %+v", test.pval, got, test.want)
  237. }
  238. }
  239. // Structs.
  240. got, err := convertParamValue(&s1ParamValue, s1ParamType)
  241. if err != nil {
  242. t.Fatal(err)
  243. }
  244. if !testutil.Equal(got, s1ParamReturnValue) {
  245. t.Errorf("got %+v, want %+v", got, s1ParamReturnValue)
  246. }
  247. }
  248. func TestIntegration_ScalarParam(t *testing.T) {
  249. roundToMicros := cmp.Transformer("RoundToMicros",
  250. func(t time.Time) time.Time { return t.Round(time.Microsecond) })
  251. c := getClient(t)
  252. for _, test := range scalarTests {
  253. gotData, gotParam, err := paramRoundTrip(c, test.val)
  254. if err != nil {
  255. t.Fatal(err)
  256. }
  257. if !testutil.Equal(gotData, test.val, roundToMicros) {
  258. t.Errorf("\ngot %#v (%T)\nwant %#v (%T)", gotData, gotData, test.val, test.val)
  259. }
  260. if !testutil.Equal(gotParam, test.val, roundToMicros) {
  261. t.Errorf("\ngot %#v (%T)\nwant %#v (%T)", gotParam, gotParam, test.val, test.val)
  262. }
  263. }
  264. }
  265. func TestIntegration_OtherParam(t *testing.T) {
  266. c := getClient(t)
  267. for _, test := range []struct {
  268. val interface{}
  269. wantData interface{}
  270. wantParam interface{}
  271. }{
  272. {[]int(nil), []Value(nil), []interface{}(nil)},
  273. {[]int{}, []Value(nil), []interface{}(nil)},
  274. {
  275. []int{1, 2},
  276. []Value{int64(1), int64(2)},
  277. []interface{}{int64(1), int64(2)},
  278. },
  279. {
  280. [3]int{1, 2, 3},
  281. []Value{int64(1), int64(2), int64(3)},
  282. []interface{}{int64(1), int64(2), int64(3)},
  283. },
  284. {
  285. S1{},
  286. []Value{int64(0), nil, false},
  287. map[string]interface{}{
  288. "A": int64(0),
  289. "B": nil,
  290. "C": false,
  291. },
  292. },
  293. {
  294. s1,
  295. []Value{int64(1), []Value{"s"}, true},
  296. s1ParamReturnValue,
  297. },
  298. } {
  299. gotData, gotParam, err := paramRoundTrip(c, test.val)
  300. if err != nil {
  301. t.Fatal(err)
  302. }
  303. if !testutil.Equal(gotData, test.wantData) {
  304. t.Errorf("%#v:\ngot %#v (%T)\nwant %#v (%T)",
  305. test.val, gotData, gotData, test.wantData, test.wantData)
  306. }
  307. if !testutil.Equal(gotParam, test.wantParam) {
  308. t.Errorf("%#v:\ngot %#v (%T)\nwant %#v (%T)",
  309. test.val, gotParam, gotParam, test.wantParam, test.wantParam)
  310. }
  311. }
  312. }
  313. // paramRoundTrip passes x as a query parameter to BigQuery. It returns
  314. // the resulting data value from running the query and the parameter value from
  315. // the returned job configuration.
  316. func paramRoundTrip(c *Client, x interface{}) (data Value, param interface{}, err error) {
  317. ctx := context.Background()
  318. q := c.Query("select ?")
  319. q.Parameters = []QueryParameter{{Value: x}}
  320. job, err := q.Run(ctx)
  321. if err != nil {
  322. return nil, nil, err
  323. }
  324. it, err := job.Read(ctx)
  325. if err != nil {
  326. return nil, nil, err
  327. }
  328. var val []Value
  329. err = it.Next(&val)
  330. if err != nil {
  331. return nil, nil, err
  332. }
  333. if len(val) != 1 {
  334. return nil, nil, errors.New("wrong number of values")
  335. }
  336. conf, err := job.Config()
  337. if err != nil {
  338. return nil, nil, err
  339. }
  340. return val[0], conf.(*QueryConfig).Parameters[0].Value, nil
  341. }
  342. func TestQueryParameter_toBQ(t *testing.T) {
  343. tests := []struct {
  344. in QueryParameter
  345. want []string
  346. }{
  347. {
  348. in: QueryParameter{Name: "name", Value: ""},
  349. want: []string{"Value"},
  350. },
  351. }
  352. for _, test := range tests {
  353. q, err := test.in.toBQ()
  354. if err != nil {
  355. t.Fatalf("expected no error, got %v", err)
  356. }
  357. got := q.ParameterValue.ForceSendFields
  358. if !cmp.Equal(test.want, got) {
  359. t.Fatalf("want %v, got %v", test.want, got)
  360. }
  361. }
  362. }