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.
 
 
 

296 lines
7.7 KiB

  1. // Copyright 2017 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. "testing"
  17. "time"
  18. "cloud.google.com/go/internal/testutil"
  19. bq "google.golang.org/api/bigquery/v2"
  20. )
  21. func TestBQToTableMetadata(t *testing.T) {
  22. aTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local)
  23. aTimeMillis := aTime.UnixNano() / 1e6
  24. for _, test := range []struct {
  25. in *bq.Table
  26. want *TableMetadata
  27. }{
  28. {&bq.Table{}, &TableMetadata{}}, // test minimal case
  29. {
  30. &bq.Table{
  31. CreationTime: aTimeMillis,
  32. Description: "desc",
  33. Etag: "etag",
  34. ExpirationTime: aTimeMillis,
  35. FriendlyName: "fname",
  36. Id: "id",
  37. LastModifiedTime: uint64(aTimeMillis),
  38. Location: "loc",
  39. NumBytes: 123,
  40. NumLongTermBytes: 23,
  41. NumRows: 7,
  42. StreamingBuffer: &bq.Streamingbuffer{
  43. EstimatedBytes: 11,
  44. EstimatedRows: 3,
  45. OldestEntryTime: uint64(aTimeMillis),
  46. },
  47. TimePartitioning: &bq.TimePartitioning{
  48. ExpirationMs: 7890,
  49. Type: "DAY",
  50. Field: "pfield",
  51. },
  52. EncryptionConfiguration: &bq.EncryptionConfiguration{KmsKeyName: "keyName"},
  53. Type: "EXTERNAL",
  54. View: &bq.ViewDefinition{Query: "view-query"},
  55. Labels: map[string]string{"a": "b"},
  56. ExternalDataConfiguration: &bq.ExternalDataConfiguration{
  57. SourceFormat: "GOOGLE_SHEETS",
  58. },
  59. },
  60. &TableMetadata{
  61. Description: "desc",
  62. Name: "fname",
  63. ViewQuery: "view-query",
  64. FullID: "id",
  65. Type: ExternalTable,
  66. Labels: map[string]string{"a": "b"},
  67. ExternalDataConfig: &ExternalDataConfig{SourceFormat: GoogleSheets},
  68. ExpirationTime: aTime.Truncate(time.Millisecond),
  69. CreationTime: aTime.Truncate(time.Millisecond),
  70. LastModifiedTime: aTime.Truncate(time.Millisecond),
  71. NumBytes: 123,
  72. NumRows: 7,
  73. TimePartitioning: &TimePartitioning{
  74. Expiration: 7890 * time.Millisecond,
  75. Field: "pfield",
  76. },
  77. StreamingBuffer: &StreamingBuffer{
  78. EstimatedBytes: 11,
  79. EstimatedRows: 3,
  80. OldestEntryTime: aTime,
  81. },
  82. EncryptionConfig: &EncryptionConfig{KMSKeyName: "keyName"},
  83. ETag: "etag",
  84. },
  85. },
  86. } {
  87. got, err := bqToTableMetadata(test.in)
  88. if err != nil {
  89. t.Fatal(err)
  90. }
  91. if diff := testutil.Diff(got, test.want); diff != "" {
  92. t.Errorf("%+v:\n, -got, +want:\n%s", test.in, diff)
  93. }
  94. }
  95. }
  96. func TestTableMetadataToBQ(t *testing.T) {
  97. aTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local)
  98. aTimeMillis := aTime.UnixNano() / 1e6
  99. sc := Schema{fieldSchema("desc", "name", "STRING", false, true)}
  100. for _, test := range []struct {
  101. in *TableMetadata
  102. want *bq.Table
  103. }{
  104. {nil, &bq.Table{}},
  105. {&TableMetadata{}, &bq.Table{}},
  106. {
  107. &TableMetadata{
  108. Name: "n",
  109. Description: "d",
  110. Schema: sc,
  111. ExpirationTime: aTime,
  112. Labels: map[string]string{"a": "b"},
  113. ExternalDataConfig: &ExternalDataConfig{SourceFormat: Bigtable},
  114. EncryptionConfig: &EncryptionConfig{KMSKeyName: "keyName"},
  115. },
  116. &bq.Table{
  117. FriendlyName: "n",
  118. Description: "d",
  119. Schema: &bq.TableSchema{
  120. Fields: []*bq.TableFieldSchema{
  121. bqTableFieldSchema("desc", "name", "STRING", "REQUIRED"),
  122. },
  123. },
  124. ExpirationTime: aTimeMillis,
  125. Labels: map[string]string{"a": "b"},
  126. ExternalDataConfiguration: &bq.ExternalDataConfiguration{SourceFormat: "BIGTABLE"},
  127. EncryptionConfiguration: &bq.EncryptionConfiguration{KmsKeyName: "keyName"},
  128. },
  129. },
  130. {
  131. &TableMetadata{ViewQuery: "q"},
  132. &bq.Table{
  133. View: &bq.ViewDefinition{
  134. Query: "q",
  135. UseLegacySql: false,
  136. ForceSendFields: []string{"UseLegacySql"},
  137. },
  138. },
  139. },
  140. {
  141. &TableMetadata{
  142. ViewQuery: "q",
  143. UseLegacySQL: true,
  144. TimePartitioning: &TimePartitioning{},
  145. },
  146. &bq.Table{
  147. View: &bq.ViewDefinition{
  148. Query: "q",
  149. UseLegacySql: true,
  150. },
  151. TimePartitioning: &bq.TimePartitioning{
  152. Type: "DAY",
  153. ExpirationMs: 0,
  154. },
  155. },
  156. },
  157. {
  158. &TableMetadata{
  159. ViewQuery: "q",
  160. UseStandardSQL: true,
  161. TimePartitioning: &TimePartitioning{
  162. Expiration: time.Second,
  163. Field: "ofDreams",
  164. },
  165. },
  166. &bq.Table{
  167. View: &bq.ViewDefinition{
  168. Query: "q",
  169. UseLegacySql: false,
  170. ForceSendFields: []string{"UseLegacySql"},
  171. },
  172. TimePartitioning: &bq.TimePartitioning{
  173. Type: "DAY",
  174. ExpirationMs: 1000,
  175. Field: "ofDreams",
  176. },
  177. },
  178. },
  179. } {
  180. got, err := test.in.toBQ()
  181. if err != nil {
  182. t.Fatalf("%+v: %v", test.in, err)
  183. }
  184. if diff := testutil.Diff(got, test.want); diff != "" {
  185. t.Errorf("%+v:\n-got, +want:\n%s", test.in, diff)
  186. }
  187. }
  188. // Errors
  189. for _, in := range []*TableMetadata{
  190. {Schema: sc, ViewQuery: "q"}, // can't have both schema and query
  191. {UseLegacySQL: true}, // UseLegacySQL without query
  192. {UseStandardSQL: true}, // UseStandardSQL without query
  193. // read-only fields
  194. {FullID: "x"},
  195. {Type: "x"},
  196. {CreationTime: aTime},
  197. {LastModifiedTime: aTime},
  198. {NumBytes: 1},
  199. {NumRows: 1},
  200. {StreamingBuffer: &StreamingBuffer{}},
  201. {ETag: "x"},
  202. } {
  203. _, err := in.toBQ()
  204. if err == nil {
  205. t.Errorf("%+v: got nil, want error", in)
  206. }
  207. }
  208. }
  209. func TestTableMetadataToUpdateToBQ(t *testing.T) {
  210. aTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local)
  211. for _, test := range []struct {
  212. tm TableMetadataToUpdate
  213. want *bq.Table
  214. }{
  215. {
  216. tm: TableMetadataToUpdate{},
  217. want: &bq.Table{},
  218. },
  219. {
  220. tm: TableMetadataToUpdate{
  221. Description: "d",
  222. Name: "n",
  223. },
  224. want: &bq.Table{
  225. Description: "d",
  226. FriendlyName: "n",
  227. ForceSendFields: []string{"Description", "FriendlyName"},
  228. },
  229. },
  230. {
  231. tm: TableMetadataToUpdate{
  232. Schema: Schema{fieldSchema("desc", "name", "STRING", false, true)},
  233. ExpirationTime: aTime,
  234. },
  235. want: &bq.Table{
  236. Schema: &bq.TableSchema{
  237. Fields: []*bq.TableFieldSchema{
  238. bqTableFieldSchema("desc", "name", "STRING", "REQUIRED"),
  239. },
  240. },
  241. ExpirationTime: aTime.UnixNano() / 1e6,
  242. ForceSendFields: []string{"Schema", "ExpirationTime"},
  243. },
  244. },
  245. {
  246. tm: TableMetadataToUpdate{ViewQuery: "q"},
  247. want: &bq.Table{
  248. View: &bq.ViewDefinition{Query: "q", ForceSendFields: []string{"Query"}},
  249. },
  250. },
  251. {
  252. tm: TableMetadataToUpdate{UseLegacySQL: false},
  253. want: &bq.Table{
  254. View: &bq.ViewDefinition{
  255. UseLegacySql: false,
  256. ForceSendFields: []string{"UseLegacySql"},
  257. },
  258. },
  259. },
  260. {
  261. tm: TableMetadataToUpdate{ViewQuery: "q", UseLegacySQL: true},
  262. want: &bq.Table{
  263. View: &bq.ViewDefinition{
  264. Query: "q",
  265. UseLegacySql: true,
  266. ForceSendFields: []string{"Query", "UseLegacySql"},
  267. },
  268. },
  269. },
  270. {
  271. tm: func() (tm TableMetadataToUpdate) {
  272. tm.SetLabel("L", "V")
  273. tm.DeleteLabel("D")
  274. return tm
  275. }(),
  276. want: &bq.Table{
  277. Labels: map[string]string{"L": "V"},
  278. NullFields: []string{"Labels.D"},
  279. },
  280. },
  281. } {
  282. got := test.tm.toBQ()
  283. if !testutil.Equal(got, test.want) {
  284. t.Errorf("%+v:\ngot %+v\nwant %+v", test.tm, got, test.want)
  285. }
  286. }
  287. }