// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package bigquery import ( "testing" "time" "cloud.google.com/go/internal/testutil" bq "google.golang.org/api/bigquery/v2" ) func TestBQTableToMetadata(t *testing.T) { aTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local) aTimeMillis := aTime.UnixNano() / 1e6 for _, test := range []struct { in *bq.Table want *TableMetadata }{ {&bq.Table{}, &TableMetadata{}}, // test minimal case { &bq.Table{ CreationTime: aTimeMillis, Description: "desc", Etag: "etag", ExpirationTime: aTimeMillis, FriendlyName: "fname", Id: "id", LastModifiedTime: uint64(aTimeMillis), Location: "loc", NumBytes: 123, NumLongTermBytes: 23, NumRows: 7, StreamingBuffer: &bq.Streamingbuffer{ EstimatedBytes: 11, EstimatedRows: 3, OldestEntryTime: uint64(aTimeMillis), }, TimePartitioning: &bq.TimePartitioning{ ExpirationMs: 7890, Type: "DAY", }, Type: "EXTERNAL", View: &bq.ViewDefinition{Query: "view-query"}, }, &TableMetadata{ Description: "desc", Name: "fname", ViewQuery: "view-query", FullID: "id", Type: ExternalTable, ExpirationTime: aTime.Truncate(time.Millisecond), CreationTime: aTime.Truncate(time.Millisecond), LastModifiedTime: aTime.Truncate(time.Millisecond), NumBytes: 123, NumRows: 7, TimePartitioning: &TimePartitioning{Expiration: 7890 * time.Millisecond}, StreamingBuffer: &StreamingBuffer{ EstimatedBytes: 11, EstimatedRows: 3, OldestEntryTime: aTime, }, ETag: "etag", }, }, } { got := bqTableToMetadata(test.in) if diff := testutil.Diff(got, test.want); diff != "" { t.Errorf("%+v:\n, -got, +want:\n%s", test.in, diff) } } } func TestBQTableFromMetadata(t *testing.T) { aTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local) aTimeMillis := aTime.UnixNano() / 1e6 sc := Schema{fieldSchema("desc", "name", "STRING", false, true)} for _, test := range []struct { in *TableMetadata want *bq.Table }{ {nil, &bq.Table{}}, {&TableMetadata{}, &bq.Table{}}, { &TableMetadata{ Name: "n", Description: "d", Schema: sc, ExpirationTime: aTime, }, &bq.Table{ FriendlyName: "n", Description: "d", Schema: &bq.TableSchema{ Fields: []*bq.TableFieldSchema{ bqTableFieldSchema("desc", "name", "STRING", "REQUIRED"), }, }, ExpirationTime: aTimeMillis, }, }, { &TableMetadata{ViewQuery: "q"}, &bq.Table{ View: &bq.ViewDefinition{ Query: "q", UseLegacySql: false, ForceSendFields: []string{"UseLegacySql"}, }, }, }, { &TableMetadata{ ViewQuery: "q", UseLegacySQL: true, TimePartitioning: &TimePartitioning{}, }, &bq.Table{ View: &bq.ViewDefinition{ Query: "q", UseLegacySql: true, }, TimePartitioning: &bq.TimePartitioning{ Type: "DAY", ExpirationMs: 0, }, }, }, { &TableMetadata{ ViewQuery: "q", UseStandardSQL: true, TimePartitioning: &TimePartitioning{time.Second}, }, &bq.Table{ View: &bq.ViewDefinition{ Query: "q", UseLegacySql: false, ForceSendFields: []string{"UseLegacySql"}, }, TimePartitioning: &bq.TimePartitioning{ Type: "DAY", ExpirationMs: 1000, }, }, }, } { got, err := bqTableFromMetadata(test.in) if err != nil { t.Fatalf("%+v: %v", test.in, err) } if diff := testutil.Diff(got, test.want); diff != "" { t.Errorf("%+v:\n-got, +want:\n%s", test.in, diff) } } // Errors for _, in := range []*TableMetadata{ {Schema: sc, ViewQuery: "q"}, // can't have both schema and query {UseLegacySQL: true}, // UseLegacySQL without query {UseStandardSQL: true}, // UseStandardSQL without query // read-only fields {FullID: "x"}, {Type: "x"}, {CreationTime: aTime}, {LastModifiedTime: aTime}, {NumBytes: 1}, {NumRows: 1}, {StreamingBuffer: &StreamingBuffer{}}, {ETag: "x"}, } { _, err := bqTableFromMetadata(in) if err == nil { t.Errorf("%+v: got nil, want error", in) } } } func TestBQDatasetFromMetadata(t *testing.T) { for _, test := range []struct { in *DatasetMetadata want *bq.Dataset }{ {nil, &bq.Dataset{}}, {&DatasetMetadata{Name: "name"}, &bq.Dataset{FriendlyName: "name"}}, {&DatasetMetadata{ Name: "name", Description: "desc", DefaultTableExpiration: time.Hour, Location: "EU", Labels: map[string]string{"x": "y"}, }, &bq.Dataset{ FriendlyName: "name", Description: "desc", DefaultTableExpirationMs: 60 * 60 * 1000, Location: "EU", Labels: map[string]string{"x": "y"}, }}, } { got, err := bqDatasetFromMetadata(test.in) if err != nil { t.Fatal(err) } if !testutil.Equal(got, test.want) { t.Errorf("%v:\ngot %+v\nwant %+v", test.in, got, test.want) } } // Check that non-writeable fields are unset. _, err := bqDatasetFromMetadata(&DatasetMetadata{FullID: "x"}) if err == nil { t.Error("got nil, want error") } } func TestBQDatasetFromUpdateMetadata(t *testing.T) { dm := DatasetMetadataToUpdate{ Description: "desc", Name: "name", DefaultTableExpiration: time.Hour, } dm.SetLabel("label", "value") dm.DeleteLabel("del") got := bqDatasetFromUpdateMetadata(&dm) want := &bq.Dataset{ Description: "desc", FriendlyName: "name", DefaultTableExpirationMs: 60 * 60 * 1000, Labels: map[string]string{"label": "value"}, ForceSendFields: []string{"Description", "FriendlyName"}, NullFields: []string{"Labels.del"}, } if diff := testutil.Diff(got, want); diff != "" { t.Errorf("-got, +want:\n%s", diff) } }