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.
 
 
 

579 lines
15 KiB

  1. // Copyright 2015 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 bigtable
  15. import (
  16. "context"
  17. "fmt"
  18. "math"
  19. "sort"
  20. "strings"
  21. "testing"
  22. "time"
  23. "cloud.google.com/go/internal/testutil"
  24. "github.com/golang/protobuf/proto"
  25. "google.golang.org/api/iterator"
  26. btapb "google.golang.org/genproto/googleapis/bigtable/admin/v2"
  27. )
  28. func TestAdminIntegration(t *testing.T) {
  29. testEnv, err := NewIntegrationEnv()
  30. if err != nil {
  31. t.Fatalf("IntegrationEnv: %v", err)
  32. }
  33. defer testEnv.Close()
  34. timeout := 2 * time.Second
  35. if testEnv.Config().UseProd {
  36. timeout = 5 * time.Minute
  37. }
  38. ctx, _ := context.WithTimeout(context.Background(), timeout)
  39. adminClient, err := testEnv.NewAdminClient()
  40. if err != nil {
  41. t.Fatalf("NewAdminClient: %v", err)
  42. }
  43. defer adminClient.Close()
  44. iAdminClient, err := testEnv.NewInstanceAdminClient()
  45. if err != nil {
  46. t.Fatalf("NewInstanceAdminClient: %v", err)
  47. }
  48. if iAdminClient != nil {
  49. defer iAdminClient.Close()
  50. iInfo, err := iAdminClient.InstanceInfo(ctx, adminClient.instance)
  51. if err != nil {
  52. t.Errorf("InstanceInfo: %v", err)
  53. }
  54. if iInfo.Name != adminClient.instance {
  55. t.Errorf("InstanceInfo returned name %#v, want %#v", iInfo.Name, adminClient.instance)
  56. }
  57. }
  58. list := func() []string {
  59. tbls, err := adminClient.Tables(ctx)
  60. if err != nil {
  61. t.Fatalf("Fetching list of tables: %v", err)
  62. }
  63. sort.Strings(tbls)
  64. return tbls
  65. }
  66. containsAll := func(got, want []string) bool {
  67. gotSet := make(map[string]bool)
  68. for _, s := range got {
  69. gotSet[s] = true
  70. }
  71. for _, s := range want {
  72. if !gotSet[s] {
  73. return false
  74. }
  75. }
  76. return true
  77. }
  78. defer adminClient.DeleteTable(ctx, "mytable")
  79. if err := adminClient.CreateTable(ctx, "mytable"); err != nil {
  80. t.Fatalf("Creating table: %v", err)
  81. }
  82. defer adminClient.DeleteTable(ctx, "myothertable")
  83. if err := adminClient.CreateTable(ctx, "myothertable"); err != nil {
  84. t.Fatalf("Creating table: %v", err)
  85. }
  86. if got, want := list(), []string{"myothertable", "mytable"}; !containsAll(got, want) {
  87. t.Errorf("adminClient.Tables returned %#v, want %#v", got, want)
  88. }
  89. must(adminClient.WaitForReplication(ctx, "mytable"))
  90. if err := adminClient.DeleteTable(ctx, "myothertable"); err != nil {
  91. t.Fatalf("Deleting table: %v", err)
  92. }
  93. tables := list()
  94. if got, want := tables, []string{"mytable"}; !containsAll(got, want) {
  95. t.Errorf("adminClient.Tables returned %#v, want %#v", got, want)
  96. }
  97. if got, unwanted := tables, []string{"myothertable"}; containsAll(got, unwanted) {
  98. t.Errorf("adminClient.Tables return %#v. unwanted %#v", got, unwanted)
  99. }
  100. tblConf := TableConf{
  101. TableID: "conftable",
  102. Families: map[string]GCPolicy{
  103. "fam1": MaxVersionsPolicy(1),
  104. "fam2": MaxVersionsPolicy(2),
  105. },
  106. }
  107. if err := adminClient.CreateTableFromConf(ctx, &tblConf); err != nil {
  108. t.Fatalf("Creating table from TableConf: %v", err)
  109. }
  110. defer adminClient.DeleteTable(ctx, tblConf.TableID)
  111. tblInfo, err := adminClient.TableInfo(ctx, tblConf.TableID)
  112. if err != nil {
  113. t.Fatalf("Getting table info: %v", err)
  114. }
  115. sort.Strings(tblInfo.Families)
  116. wantFams := []string{"fam1", "fam2"}
  117. if !testutil.Equal(tblInfo.Families, wantFams) {
  118. t.Errorf("Column family mismatch, got %v, want %v", tblInfo.Families, wantFams)
  119. }
  120. // Populate mytable and drop row ranges
  121. if err = adminClient.CreateColumnFamily(ctx, "mytable", "cf"); err != nil {
  122. t.Fatalf("Creating column family: %v", err)
  123. }
  124. client, err := testEnv.NewClient()
  125. if err != nil {
  126. t.Fatalf("NewClient: %v", err)
  127. }
  128. defer client.Close()
  129. tbl := client.Open("mytable")
  130. prefixes := []string{"a", "b", "c"}
  131. for _, prefix := range prefixes {
  132. for i := 0; i < 5; i++ {
  133. mut := NewMutation()
  134. mut.Set("cf", "col", 1000, []byte("1"))
  135. if err := tbl.Apply(ctx, fmt.Sprintf("%v-%v", prefix, i), mut); err != nil {
  136. t.Fatalf("Mutating row: %v", err)
  137. }
  138. }
  139. }
  140. if err = adminClient.DropRowRange(ctx, "mytable", "a"); err != nil {
  141. t.Errorf("DropRowRange a: %v", err)
  142. }
  143. if err = adminClient.DropRowRange(ctx, "mytable", "c"); err != nil {
  144. t.Errorf("DropRowRange c: %v", err)
  145. }
  146. if err = adminClient.DropRowRange(ctx, "mytable", "x"); err != nil {
  147. t.Errorf("DropRowRange x: %v", err)
  148. }
  149. var gotRowCount int
  150. must(tbl.ReadRows(ctx, RowRange{}, func(row Row) bool {
  151. gotRowCount++
  152. if !strings.HasPrefix(row.Key(), "b") {
  153. t.Errorf("Invalid row after dropping range: %v", row)
  154. }
  155. return true
  156. }))
  157. if gotRowCount != 5 {
  158. t.Errorf("Invalid row count after dropping range: got %v, want %v", gotRowCount, 5)
  159. }
  160. }
  161. func TestInstanceUpdate(t *testing.T) {
  162. testEnv, err := NewIntegrationEnv()
  163. if err != nil {
  164. t.Fatalf("IntegrationEnv: %v", err)
  165. }
  166. defer testEnv.Close()
  167. timeout := 2 * time.Second
  168. if testEnv.Config().UseProd {
  169. timeout = 5 * time.Minute
  170. }
  171. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  172. defer cancel()
  173. adminClient, err := testEnv.NewAdminClient()
  174. if err != nil {
  175. t.Fatalf("NewAdminClient: %v", err)
  176. }
  177. defer adminClient.Close()
  178. iAdminClient, err := testEnv.NewInstanceAdminClient()
  179. if err != nil {
  180. t.Fatalf("NewInstanceAdminClient: %v", err)
  181. }
  182. if iAdminClient == nil {
  183. return
  184. }
  185. defer iAdminClient.Close()
  186. iInfo, err := iAdminClient.InstanceInfo(ctx, adminClient.instance)
  187. if err != nil {
  188. t.Errorf("InstanceInfo: %v", err)
  189. }
  190. if iInfo.Name != adminClient.instance {
  191. t.Errorf("InstanceInfo returned name %#v, want %#v", iInfo.Name, adminClient.instance)
  192. }
  193. if iInfo.DisplayName != adminClient.instance {
  194. t.Errorf("InstanceInfo returned name %#v, want %#v", iInfo.Name, adminClient.instance)
  195. }
  196. const numNodes = 4
  197. // update cluster nodes
  198. if err := iAdminClient.UpdateCluster(ctx, adminClient.instance, testEnv.Config().Cluster, int32(numNodes)); err != nil {
  199. t.Errorf("UpdateCluster: %v", err)
  200. }
  201. // get cluster after updating
  202. cis, err := iAdminClient.GetCluster(ctx, adminClient.instance, testEnv.Config().Cluster)
  203. if err != nil {
  204. t.Errorf("GetCluster %v", err)
  205. }
  206. if cis.ServeNodes != int(numNodes) {
  207. t.Errorf("ServeNodes returned %d, want %d", cis.ServeNodes, int(numNodes))
  208. }
  209. }
  210. func TestAdminSnapshotIntegration(t *testing.T) {
  211. testEnv, err := NewIntegrationEnv()
  212. if err != nil {
  213. t.Fatalf("IntegrationEnv: %v", err)
  214. }
  215. defer testEnv.Close()
  216. if !testEnv.Config().UseProd {
  217. t.Skip("emulator doesn't support snapshots")
  218. }
  219. timeout := 2 * time.Second
  220. if testEnv.Config().UseProd {
  221. timeout = 5 * time.Minute
  222. }
  223. ctx, _ := context.WithTimeout(context.Background(), timeout)
  224. adminClient, err := testEnv.NewAdminClient()
  225. if err != nil {
  226. t.Fatalf("NewAdminClient: %v", err)
  227. }
  228. defer adminClient.Close()
  229. table := testEnv.Config().Table
  230. cluster := testEnv.Config().Cluster
  231. list := func(cluster string) ([]*SnapshotInfo, error) {
  232. infos := []*SnapshotInfo(nil)
  233. it := adminClient.Snapshots(ctx, cluster)
  234. for {
  235. s, err := it.Next()
  236. if err == iterator.Done {
  237. break
  238. }
  239. if err != nil {
  240. return nil, err
  241. }
  242. infos = append(infos, s)
  243. }
  244. return infos, err
  245. }
  246. // Delete the table at the end of the test. Schedule ahead of time
  247. // in case the client fails
  248. defer adminClient.DeleteTable(ctx, table)
  249. if err := adminClient.CreateTable(ctx, table); err != nil {
  250. t.Fatalf("Creating table: %v", err)
  251. }
  252. // Precondition: no snapshots
  253. snapshots, err := list(cluster)
  254. if err != nil {
  255. t.Fatalf("Initial snapshot list: %v", err)
  256. }
  257. if got, want := len(snapshots), 0; got != want {
  258. t.Fatalf("Initial snapshot list len: %d, want: %d", got, want)
  259. }
  260. // Create snapshot
  261. defer adminClient.DeleteSnapshot(ctx, cluster, "mysnapshot")
  262. if err = adminClient.SnapshotTable(ctx, table, cluster, "mysnapshot", 5*time.Hour); err != nil {
  263. t.Fatalf("Creating snaphot: %v", err)
  264. }
  265. // List snapshot
  266. snapshots, err = list(cluster)
  267. if err != nil {
  268. t.Fatalf("Listing snapshots: %v", err)
  269. }
  270. if got, want := len(snapshots), 1; got != want {
  271. t.Fatalf("Listing snapshot count: %d, want: %d", got, want)
  272. }
  273. if got, want := snapshots[0].Name, "mysnapshot"; got != want {
  274. t.Fatalf("Snapshot name: %s, want: %s", got, want)
  275. }
  276. if got, want := snapshots[0].SourceTable, table; got != want {
  277. t.Fatalf("Snapshot SourceTable: %s, want: %s", got, want)
  278. }
  279. if got, want := snapshots[0].DeleteTime, snapshots[0].CreateTime.Add(5*time.Hour); math.Abs(got.Sub(want).Minutes()) > 1 {
  280. t.Fatalf("Snapshot DeleteTime: %s, want: %s", got, want)
  281. }
  282. // Get snapshot
  283. snapshot, err := adminClient.SnapshotInfo(ctx, cluster, "mysnapshot")
  284. if err != nil {
  285. t.Fatalf("SnapshotInfo: %v", snapshot)
  286. }
  287. if got, want := *snapshot, *snapshots[0]; got != want {
  288. t.Fatalf("SnapshotInfo: %v, want: %v", got, want)
  289. }
  290. // Restore
  291. restoredTable := table + "-restored"
  292. defer adminClient.DeleteTable(ctx, restoredTable)
  293. if err = adminClient.CreateTableFromSnapshot(ctx, restoredTable, cluster, "mysnapshot"); err != nil {
  294. t.Fatalf("CreateTableFromSnapshot: %v", err)
  295. }
  296. if _, err := adminClient.TableInfo(ctx, restoredTable); err != nil {
  297. t.Fatalf("Restored TableInfo: %v", err)
  298. }
  299. // Delete snapshot
  300. if err = adminClient.DeleteSnapshot(ctx, cluster, "mysnapshot"); err != nil {
  301. t.Fatalf("DeleteSnapshot: %v", err)
  302. }
  303. snapshots, err = list(cluster)
  304. if err != nil {
  305. t.Fatalf("List after Delete: %v", err)
  306. }
  307. if got, want := len(snapshots), 0; got != want {
  308. t.Fatalf("List after delete len: %d, want: %d", got, want)
  309. }
  310. }
  311. func TestGranularity(t *testing.T) {
  312. testEnv, err := NewIntegrationEnv()
  313. if err != nil {
  314. t.Fatalf("IntegrationEnv: %v", err)
  315. }
  316. defer testEnv.Close()
  317. timeout := 2 * time.Second
  318. if testEnv.Config().UseProd {
  319. timeout = 5 * time.Minute
  320. }
  321. ctx, _ := context.WithTimeout(context.Background(), timeout)
  322. adminClient, err := testEnv.NewAdminClient()
  323. if err != nil {
  324. t.Fatalf("NewAdminClient: %v", err)
  325. }
  326. defer adminClient.Close()
  327. list := func() []string {
  328. tbls, err := adminClient.Tables(ctx)
  329. if err != nil {
  330. t.Fatalf("Fetching list of tables: %v", err)
  331. }
  332. sort.Strings(tbls)
  333. return tbls
  334. }
  335. containsAll := func(got, want []string) bool {
  336. gotSet := make(map[string]bool)
  337. for _, s := range got {
  338. gotSet[s] = true
  339. }
  340. for _, s := range want {
  341. if !gotSet[s] {
  342. return false
  343. }
  344. }
  345. return true
  346. }
  347. defer adminClient.DeleteTable(ctx, "mytable")
  348. if err := adminClient.CreateTable(ctx, "mytable"); err != nil {
  349. t.Fatalf("Creating table: %v", err)
  350. }
  351. tables := list()
  352. if got, want := tables, []string{"mytable"}; !containsAll(got, want) {
  353. t.Errorf("adminClient.Tables returned %#v, want %#v", got, want)
  354. }
  355. // calling ModifyColumnFamilies to check the granularity of table
  356. prefix := adminClient.instancePrefix()
  357. req := &btapb.ModifyColumnFamiliesRequest{
  358. Name: prefix + "/tables/" + "mytable",
  359. Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{
  360. Id: "cf",
  361. Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Create{&btapb.ColumnFamily{}},
  362. }},
  363. }
  364. table, err := adminClient.tClient.ModifyColumnFamilies(ctx, req)
  365. if err != nil {
  366. t.Fatalf("Creating column family: %v", err)
  367. }
  368. if table.Granularity != btapb.Table_TimestampGranularity(btapb.Table_MILLIS) {
  369. t.Errorf("ModifyColumnFamilies returned granularity %#v, want %#v", table.Granularity, btapb.Table_TimestampGranularity(btapb.Table_MILLIS))
  370. }
  371. }
  372. func TestInstanceAdminClient_AppProfile(t *testing.T) {
  373. testEnv, err := NewIntegrationEnv()
  374. if err != nil {
  375. t.Fatalf("IntegrationEnv: %v", err)
  376. }
  377. defer testEnv.Close()
  378. timeout := 2 * time.Second
  379. if testEnv.Config().UseProd {
  380. timeout = 5 * time.Minute
  381. }
  382. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  383. defer cancel()
  384. adminClient, err := testEnv.NewAdminClient()
  385. if err != nil {
  386. t.Fatalf("NewAdminClient: %v", err)
  387. }
  388. defer adminClient.Close()
  389. iAdminClient, err := testEnv.NewInstanceAdminClient()
  390. if err != nil {
  391. t.Fatalf("NewInstanceAdminClient: %v", err)
  392. }
  393. if iAdminClient == nil {
  394. return
  395. }
  396. defer iAdminClient.Close()
  397. profile := ProfileConf{
  398. ProfileID: "app_profile1",
  399. InstanceID: adminClient.instance,
  400. ClusterID: testEnv.Config().Cluster,
  401. Description: "creating new app profile 1",
  402. RoutingPolicy: SingleClusterRouting,
  403. }
  404. createdProfile, err := iAdminClient.CreateAppProfile(ctx, profile)
  405. if err != nil {
  406. t.Fatalf("Creating app profile: %v", err)
  407. }
  408. gotProfile, err := iAdminClient.GetAppProfile(ctx, adminClient.instance, "app_profile1")
  409. if err != nil {
  410. t.Fatalf("Get app profile: %v", err)
  411. }
  412. if !proto.Equal(createdProfile, gotProfile) {
  413. t.Fatalf("created profile: %s, got profile: %s", createdProfile.Name, gotProfile.Name)
  414. }
  415. list := func(instanceID string) ([]*btapb.AppProfile, error) {
  416. profiles := []*btapb.AppProfile(nil)
  417. it := iAdminClient.ListAppProfiles(ctx, instanceID)
  418. for {
  419. s, err := it.Next()
  420. if err == iterator.Done {
  421. break
  422. }
  423. if err != nil {
  424. return nil, err
  425. }
  426. profiles = append(profiles, s)
  427. }
  428. return profiles, err
  429. }
  430. profiles, err := list(adminClient.instance)
  431. if err != nil {
  432. t.Fatalf("List app profile: %v", err)
  433. }
  434. if got, want := len(profiles), 1; got != want {
  435. t.Fatalf("Initial app profile list len: %d, want: %d", got, want)
  436. }
  437. for _, test := range []struct {
  438. desc string
  439. uattrs ProfileAttrsToUpdate
  440. want *btapb.AppProfile // nil means error
  441. }{
  442. {
  443. desc: "empty update",
  444. uattrs: ProfileAttrsToUpdate{},
  445. want: nil,
  446. },
  447. {
  448. desc: "empty description update",
  449. uattrs: ProfileAttrsToUpdate{Description: ""},
  450. want: &btapb.AppProfile{
  451. Name: gotProfile.Name,
  452. Description: "",
  453. RoutingPolicy: gotProfile.RoutingPolicy,
  454. Etag: gotProfile.Etag},
  455. },
  456. {
  457. desc: "routing update",
  458. uattrs: ProfileAttrsToUpdate{
  459. RoutingPolicy: SingleClusterRouting,
  460. ClusterID: testEnv.Config().Cluster,
  461. },
  462. want: &btapb.AppProfile{
  463. Name: gotProfile.Name,
  464. Description: "",
  465. Etag: gotProfile.Etag,
  466. RoutingPolicy: &btapb.AppProfile_SingleClusterRouting_{
  467. SingleClusterRouting: &btapb.AppProfile_SingleClusterRouting{
  468. ClusterId: testEnv.Config().Cluster,
  469. }},
  470. },
  471. },
  472. } {
  473. err = iAdminClient.UpdateAppProfile(ctx, adminClient.instance, "app_profile1", test.uattrs)
  474. if err != nil {
  475. if test.want != nil {
  476. t.Errorf("%s: %v", test.desc, err)
  477. }
  478. continue
  479. }
  480. if err == nil && test.want == nil {
  481. t.Errorf("%s: got nil, want error", test.desc)
  482. continue
  483. }
  484. got, _ := iAdminClient.GetAppProfile(ctx, adminClient.instance, "app_profile1")
  485. if !proto.Equal(got, test.want) {
  486. t.Fatalf("%s : got profile : %v, want profile: %v", test.desc, gotProfile, test.want)
  487. }
  488. }
  489. err = iAdminClient.DeleteAppProfile(ctx, adminClient.instance, "app_profile1")
  490. if err != nil {
  491. t.Fatalf("Delete app profile: %v", err)
  492. }
  493. }