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.
 
 
 

571 lines
16 KiB

  1. /*
  2. Copyright 2017 Google LLC
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package spanner
  14. import (
  15. "sort"
  16. "strings"
  17. "testing"
  18. proto3 "github.com/golang/protobuf/ptypes/struct"
  19. sppb "google.golang.org/genproto/googleapis/spanner/v1"
  20. )
  21. // keysetProto returns protobuf encoding of valid spanner.KeySet.
  22. func keysetProto(t *testing.T, ks KeySet) *sppb.KeySet {
  23. k, err := ks.keySetProto()
  24. if err != nil {
  25. t.Fatalf("cannot convert keyset %v to protobuf: %v", ks, err)
  26. }
  27. return k
  28. }
  29. // Test encoding from spanner.Mutation to protobuf.
  30. func TestMutationToProto(t *testing.T) {
  31. for i, test := range []struct {
  32. m *Mutation
  33. want *sppb.Mutation
  34. }{
  35. // Delete Mutation
  36. {
  37. &Mutation{opDelete, "t_foo", Key{"foo"}, nil, nil},
  38. &sppb.Mutation{
  39. Operation: &sppb.Mutation_Delete_{
  40. Delete: &sppb.Mutation_Delete{
  41. Table: "t_foo",
  42. KeySet: keysetProto(t, Key{"foo"}),
  43. },
  44. },
  45. },
  46. },
  47. // Insert Mutation
  48. {
  49. &Mutation{opInsert, "t_foo", KeySets(), []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}},
  50. &sppb.Mutation{
  51. Operation: &sppb.Mutation_Insert{
  52. Insert: &sppb.Mutation_Write{
  53. Table: "t_foo",
  54. Columns: []string{"col1", "col2"},
  55. Values: []*proto3.ListValue{
  56. {
  57. Values: []*proto3.Value{intProto(1), intProto(2)},
  58. },
  59. },
  60. },
  61. },
  62. },
  63. },
  64. // InsertOrUpdate Mutation
  65. {
  66. &Mutation{opInsertOrUpdate, "t_foo", KeySets(), []string{"col1", "col2"}, []interface{}{1.0, 2.0}},
  67. &sppb.Mutation{
  68. Operation: &sppb.Mutation_InsertOrUpdate{
  69. InsertOrUpdate: &sppb.Mutation_Write{
  70. Table: "t_foo",
  71. Columns: []string{"col1", "col2"},
  72. Values: []*proto3.ListValue{
  73. {
  74. Values: []*proto3.Value{floatProto(1.0), floatProto(2.0)},
  75. },
  76. },
  77. },
  78. },
  79. },
  80. },
  81. // Replace Mutation
  82. {
  83. &Mutation{opReplace, "t_foo", KeySets(), []string{"col1", "col2"}, []interface{}{"one", 2.0}},
  84. &sppb.Mutation{
  85. Operation: &sppb.Mutation_Replace{
  86. Replace: &sppb.Mutation_Write{
  87. Table: "t_foo",
  88. Columns: []string{"col1", "col2"},
  89. Values: []*proto3.ListValue{
  90. {
  91. Values: []*proto3.Value{stringProto("one"), floatProto(2.0)},
  92. },
  93. },
  94. },
  95. },
  96. },
  97. },
  98. // Update Mutation
  99. {
  100. &Mutation{opUpdate, "t_foo", KeySets(), []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}},
  101. &sppb.Mutation{
  102. Operation: &sppb.Mutation_Update{
  103. Update: &sppb.Mutation_Write{
  104. Table: "t_foo",
  105. Columns: []string{"col1", "col2"},
  106. Values: []*proto3.ListValue{
  107. {
  108. Values: []*proto3.Value{stringProto("one"), nullProto()},
  109. },
  110. },
  111. },
  112. },
  113. },
  114. },
  115. } {
  116. if got, err := test.m.proto(); err != nil || !testEqual(got, test.want) {
  117. t.Errorf("%d: (%#v).proto() = (%v, %v), want (%v, nil)", i, test.m, got, err, test.want)
  118. }
  119. }
  120. }
  121. // mutationColumnSorter implements sort.Interface for sorting column-value pairs in a Mutation by column names.
  122. type mutationColumnSorter struct {
  123. Mutation
  124. }
  125. // newMutationColumnSorter creates new instance of mutationColumnSorter by duplicating the input Mutation so that
  126. // sorting won't change the input Mutation.
  127. func newMutationColumnSorter(m *Mutation) *mutationColumnSorter {
  128. return &mutationColumnSorter{
  129. Mutation{
  130. m.op,
  131. m.table,
  132. m.keySet,
  133. append([]string(nil), m.columns...),
  134. append([]interface{}(nil), m.values...),
  135. },
  136. }
  137. }
  138. // Len implements sort.Interface.Len.
  139. func (ms *mutationColumnSorter) Len() int {
  140. return len(ms.columns)
  141. }
  142. // Swap implements sort.Interface.Swap.
  143. func (ms *mutationColumnSorter) Swap(i, j int) {
  144. ms.columns[i], ms.columns[j] = ms.columns[j], ms.columns[i]
  145. ms.values[i], ms.values[j] = ms.values[j], ms.values[i]
  146. }
  147. // Less implements sort.Interface.Less.
  148. func (ms *mutationColumnSorter) Less(i, j int) bool {
  149. return strings.Compare(ms.columns[i], ms.columns[j]) < 0
  150. }
  151. // mutationEqual returns true if two mutations in question are equal
  152. // to each other.
  153. func mutationEqual(t *testing.T, m1, m2 Mutation) bool {
  154. // Two mutations are considered to be equal even if their column values have different
  155. // orders.
  156. ms1 := newMutationColumnSorter(&m1)
  157. ms2 := newMutationColumnSorter(&m2)
  158. sort.Sort(ms1)
  159. sort.Sort(ms2)
  160. return testEqual(ms1, ms2)
  161. }
  162. // Test helper functions which help to generate spanner.Mutation.
  163. func TestMutationHelpers(t *testing.T) {
  164. for _, test := range []struct {
  165. m string
  166. got *Mutation
  167. want *Mutation
  168. }{
  169. {
  170. "Insert",
  171. Insert("t_foo", []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}),
  172. &Mutation{opInsert, "t_foo", nil, []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}},
  173. },
  174. {
  175. "InsertMap",
  176. InsertMap("t_foo", map[string]interface{}{"col1": int64(1), "col2": int64(2)}),
  177. &Mutation{opInsert, "t_foo", nil, []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}},
  178. },
  179. {
  180. "InsertStruct",
  181. func() *Mutation {
  182. m, err := InsertStruct(
  183. "t_foo",
  184. struct {
  185. notCol bool
  186. Col1 int64 `spanner:"col1"`
  187. Col2 int64 `spanner:"col2"`
  188. }{false, int64(1), int64(2)},
  189. )
  190. if err != nil {
  191. t.Errorf("cannot convert struct into mutation: %v", err)
  192. }
  193. return m
  194. }(),
  195. &Mutation{opInsert, "t_foo", nil, []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}},
  196. },
  197. {
  198. "Update",
  199. Update("t_foo", []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}),
  200. &Mutation{opUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}},
  201. },
  202. {
  203. "UpdateMap",
  204. UpdateMap("t_foo", map[string]interface{}{"col1": "one", "col2": []byte(nil)}),
  205. &Mutation{opUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}},
  206. },
  207. {
  208. "UpdateStruct",
  209. func() *Mutation {
  210. m, err := UpdateStruct(
  211. "t_foo",
  212. struct {
  213. Col1 string `spanner:"col1"`
  214. notCol int
  215. Col2 []byte `spanner:"col2"`
  216. }{"one", 1, nil},
  217. )
  218. if err != nil {
  219. t.Errorf("cannot convert struct into mutation: %v", err)
  220. }
  221. return m
  222. }(),
  223. &Mutation{opUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}},
  224. },
  225. {
  226. "InsertOrUpdate",
  227. InsertOrUpdate("t_foo", []string{"col1", "col2"}, []interface{}{1.0, 2.0}),
  228. &Mutation{opInsertOrUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{1.0, 2.0}},
  229. },
  230. {
  231. "InsertOrUpdateMap",
  232. InsertOrUpdateMap("t_foo", map[string]interface{}{"col1": 1.0, "col2": 2.0}),
  233. &Mutation{opInsertOrUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{1.0, 2.0}},
  234. },
  235. {
  236. "InsertOrUpdateStruct",
  237. func() *Mutation {
  238. m, err := InsertOrUpdateStruct(
  239. "t_foo",
  240. struct {
  241. Col1 float64 `spanner:"col1"`
  242. Col2 float64 `spanner:"col2"`
  243. notCol float64
  244. }{1.0, 2.0, 3.0},
  245. )
  246. if err != nil {
  247. t.Errorf("cannot convert struct into mutation: %v", err)
  248. }
  249. return m
  250. }(),
  251. &Mutation{opInsertOrUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{1.0, 2.0}},
  252. },
  253. {
  254. "Replace",
  255. Replace("t_foo", []string{"col1", "col2"}, []interface{}{"one", 2.0}),
  256. &Mutation{opReplace, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", 2.0}},
  257. },
  258. {
  259. "ReplaceMap",
  260. ReplaceMap("t_foo", map[string]interface{}{"col1": "one", "col2": 2.0}),
  261. &Mutation{opReplace, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", 2.0}},
  262. },
  263. {
  264. "ReplaceStruct",
  265. func() *Mutation {
  266. m, err := ReplaceStruct(
  267. "t_foo",
  268. struct {
  269. Col1 string `spanner:"col1"`
  270. Col2 float64 `spanner:"col2"`
  271. notCol string
  272. }{"one", 2.0, "foo"},
  273. )
  274. if err != nil {
  275. t.Errorf("cannot convert struct into mutation: %v", err)
  276. }
  277. return m
  278. }(),
  279. &Mutation{opReplace, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", 2.0}},
  280. },
  281. {
  282. "Delete",
  283. Delete("t_foo", Key{"foo"}),
  284. &Mutation{opDelete, "t_foo", Key{"foo"}, nil, nil},
  285. },
  286. {
  287. "DeleteRange",
  288. Delete("t_foo", KeyRange{Key{"bar"}, Key{"foo"}, ClosedClosed}),
  289. &Mutation{opDelete, "t_foo", KeyRange{Key{"bar"}, Key{"foo"}, ClosedClosed}, nil, nil},
  290. },
  291. } {
  292. if !mutationEqual(t, *test.got, *test.want) {
  293. t.Errorf("%v: got Mutation %v, want %v", test.m, test.got, test.want)
  294. }
  295. }
  296. }
  297. // Test encoding non-struct types by using *Struct helpers.
  298. func TestBadStructs(t *testing.T) {
  299. val := "i_am_not_a_struct"
  300. wantErr := errNotStruct(val)
  301. if _, gotErr := InsertStruct("t_test", val); !testEqual(gotErr, wantErr) {
  302. t.Errorf("InsertStruct(%q) returns error %v, want %v", val, gotErr, wantErr)
  303. }
  304. if _, gotErr := InsertOrUpdateStruct("t_test", val); !testEqual(gotErr, wantErr) {
  305. t.Errorf("InsertOrUpdateStruct(%q) returns error %v, want %v", val, gotErr, wantErr)
  306. }
  307. if _, gotErr := UpdateStruct("t_test", val); !testEqual(gotErr, wantErr) {
  308. t.Errorf("UpdateStruct(%q) returns error %v, want %v", val, gotErr, wantErr)
  309. }
  310. if _, gotErr := ReplaceStruct("t_test", val); !testEqual(gotErr, wantErr) {
  311. t.Errorf("ReplaceStruct(%q) returns error %v, want %v", val, gotErr, wantErr)
  312. }
  313. }
  314. func TestStructToMutationParams(t *testing.T) {
  315. // Tests cases not covered elsewhere.
  316. type S struct{ F interface{} }
  317. for _, test := range []struct {
  318. in interface{}
  319. wantCols []string
  320. wantVals []interface{}
  321. wantErr error
  322. }{
  323. {nil, nil, nil, errNotStruct(nil)},
  324. {3, nil, nil, errNotStruct(3)},
  325. {(*S)(nil), nil, nil, nil},
  326. {&S{F: 1}, []string{"F"}, []interface{}{1}, nil},
  327. {&S{F: CommitTimestamp}, []string{"F"}, []interface{}{CommitTimestamp}, nil},
  328. } {
  329. gotCols, gotVals, gotErr := structToMutationParams(test.in)
  330. if !testEqual(gotCols, test.wantCols) {
  331. t.Errorf("%#v: got cols %v, want %v", test.in, gotCols, test.wantCols)
  332. }
  333. if !testEqual(gotVals, test.wantVals) {
  334. t.Errorf("%#v: got vals %v, want %v", test.in, gotVals, test.wantVals)
  335. }
  336. if !testEqual(gotErr, test.wantErr) {
  337. t.Errorf("%#v: got err %v, want %v", test.in, gotErr, test.wantErr)
  338. }
  339. }
  340. }
  341. // Test encoding Mutation into proto.
  342. func TestEncodeMutation(t *testing.T) {
  343. for _, test := range []struct {
  344. name string
  345. mutation Mutation
  346. wantProto *sppb.Mutation
  347. wantErr error
  348. }{
  349. {
  350. "OpDelete",
  351. Mutation{opDelete, "t_test", Key{1}, nil, nil},
  352. &sppb.Mutation{
  353. Operation: &sppb.Mutation_Delete_{
  354. Delete: &sppb.Mutation_Delete{
  355. Table: "t_test",
  356. KeySet: &sppb.KeySet{
  357. Keys: []*proto3.ListValue{listValueProto(intProto(1))},
  358. },
  359. },
  360. },
  361. },
  362. nil,
  363. },
  364. {
  365. "OpDelete - Key error",
  366. Mutation{opDelete, "t_test", Key{struct{}{}}, nil, nil},
  367. &sppb.Mutation{
  368. Operation: &sppb.Mutation_Delete_{
  369. Delete: &sppb.Mutation_Delete{
  370. Table: "t_test",
  371. KeySet: &sppb.KeySet{},
  372. },
  373. },
  374. },
  375. errInvdKeyPartType(struct{}{}),
  376. },
  377. {
  378. "OpInsert",
  379. Mutation{opInsert, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}},
  380. &sppb.Mutation{
  381. Operation: &sppb.Mutation_Insert{
  382. Insert: &sppb.Mutation_Write{
  383. Table: "t_test",
  384. Columns: []string{"key", "val"},
  385. Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))},
  386. },
  387. },
  388. },
  389. nil,
  390. },
  391. {
  392. "OpInsert - Value Type Error",
  393. Mutation{opInsert, "t_test", nil, []string{"key", "val"}, []interface{}{struct{}{}, 1}},
  394. &sppb.Mutation{
  395. Operation: &sppb.Mutation_Insert{
  396. Insert: &sppb.Mutation_Write{},
  397. },
  398. },
  399. errEncoderUnsupportedType(struct{}{}),
  400. },
  401. {
  402. "OpInsertOrUpdate",
  403. Mutation{opInsertOrUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}},
  404. &sppb.Mutation{
  405. Operation: &sppb.Mutation_InsertOrUpdate{
  406. InsertOrUpdate: &sppb.Mutation_Write{
  407. Table: "t_test",
  408. Columns: []string{"key", "val"},
  409. Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))},
  410. },
  411. },
  412. },
  413. nil,
  414. },
  415. {
  416. "OpInsertOrUpdate - Value Type Error",
  417. Mutation{opInsertOrUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{struct{}{}, 1}},
  418. &sppb.Mutation{
  419. Operation: &sppb.Mutation_InsertOrUpdate{
  420. InsertOrUpdate: &sppb.Mutation_Write{},
  421. },
  422. },
  423. errEncoderUnsupportedType(struct{}{}),
  424. },
  425. {
  426. "OpReplace",
  427. Mutation{opReplace, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}},
  428. &sppb.Mutation{
  429. Operation: &sppb.Mutation_Replace{
  430. Replace: &sppb.Mutation_Write{
  431. Table: "t_test",
  432. Columns: []string{"key", "val"},
  433. Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))},
  434. },
  435. },
  436. },
  437. nil,
  438. },
  439. {
  440. "OpReplace - Value Type Error",
  441. Mutation{opReplace, "t_test", nil, []string{"key", "val"}, []interface{}{struct{}{}, 1}},
  442. &sppb.Mutation{
  443. Operation: &sppb.Mutation_Replace{
  444. Replace: &sppb.Mutation_Write{},
  445. },
  446. },
  447. errEncoderUnsupportedType(struct{}{}),
  448. },
  449. {
  450. "OpUpdate",
  451. Mutation{opUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}},
  452. &sppb.Mutation{
  453. Operation: &sppb.Mutation_Update{
  454. Update: &sppb.Mutation_Write{
  455. Table: "t_test",
  456. Columns: []string{"key", "val"},
  457. Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))},
  458. },
  459. },
  460. },
  461. nil,
  462. },
  463. {
  464. "OpUpdate - Value Type Error",
  465. Mutation{opUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{struct{}{}, 1}},
  466. &sppb.Mutation{
  467. Operation: &sppb.Mutation_Update{
  468. Update: &sppb.Mutation_Write{},
  469. },
  470. },
  471. errEncoderUnsupportedType(struct{}{}),
  472. },
  473. {
  474. "OpKnown - Unknown Mutation Operation Code",
  475. Mutation{op(100), "t_test", nil, nil, nil},
  476. &sppb.Mutation{},
  477. errInvdMutationOp(Mutation{op(100), "t_test", nil, nil, nil}),
  478. },
  479. } {
  480. gotProto, gotErr := test.mutation.proto()
  481. if gotErr != nil {
  482. if !testEqual(gotErr, test.wantErr) {
  483. t.Errorf("%s: %v.proto() returns error %v, want %v", test.name, test.mutation, gotErr, test.wantErr)
  484. }
  485. continue
  486. }
  487. if !testEqual(gotProto, test.wantProto) {
  488. t.Errorf("%s: %v.proto() = (%v, nil), want (%v, nil)", test.name, test.mutation, gotProto, test.wantProto)
  489. }
  490. }
  491. }
  492. // Test Encoding an array of mutations.
  493. func TestEncodeMutationArray(t *testing.T) {
  494. for _, test := range []struct {
  495. name string
  496. ms []*Mutation
  497. want []*sppb.Mutation
  498. wantErr error
  499. }{
  500. {
  501. "Multiple Mutations",
  502. []*Mutation{
  503. {opDelete, "t_test", Key{"bar"}, nil, nil},
  504. {opInsertOrUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}},
  505. },
  506. []*sppb.Mutation{
  507. {
  508. Operation: &sppb.Mutation_Delete_{
  509. Delete: &sppb.Mutation_Delete{
  510. Table: "t_test",
  511. KeySet: &sppb.KeySet{
  512. Keys: []*proto3.ListValue{listValueProto(stringProto("bar"))},
  513. },
  514. },
  515. },
  516. },
  517. {
  518. Operation: &sppb.Mutation_InsertOrUpdate{
  519. InsertOrUpdate: &sppb.Mutation_Write{
  520. Table: "t_test",
  521. Columns: []string{"key", "val"},
  522. Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))},
  523. },
  524. },
  525. },
  526. },
  527. nil,
  528. },
  529. {
  530. "Multiple Mutations - Bad Mutation",
  531. []*Mutation{
  532. {opDelete, "t_test", Key{"bar"}, nil, nil},
  533. {opInsertOrUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", struct{}{}}},
  534. },
  535. []*sppb.Mutation{},
  536. errEncoderUnsupportedType(struct{}{}),
  537. },
  538. } {
  539. gotProto, gotErr := mutationsProto(test.ms)
  540. if gotErr != nil {
  541. if !testEqual(gotErr, test.wantErr) {
  542. t.Errorf("%v: mutationsProto(%v) returns error %v, want %v", test.name, test.ms, gotErr, test.wantErr)
  543. }
  544. continue
  545. }
  546. if !testEqual(gotProto, test.want) {
  547. t.Errorf("%v: mutationsProto(%v) = (%v, nil), want (%v, nil)", test.name, test.ms, gotProto, test.want)
  548. }
  549. }
  550. }