Skip to content

Commit 701e848

Browse files
Extend bqfake Client, Dataset, and Table (#164)
1 parent abc4548 commit 701e848

File tree

3 files changed

+159
-13
lines changed

3 files changed

+159
-13
lines changed

cloudtest/bqfake/bqfake.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ type Table struct {
2727
name string
2828
// NOTE: TableType is used to indicate if this is initialized
2929
metadata *bigquery.TableMetadata
30+
err error
31+
}
32+
33+
// NewTable returns a new instance of Table.
34+
func NewTable(ds Dataset, name string, md *bigquery.TableMetadata, err error) *Table {
35+
return &Table{
36+
ds: ds,
37+
name: name,
38+
metadata: md,
39+
err: err,
40+
}
3041
}
3142

3243
// ProjectID implements the bqiface method.
@@ -80,10 +91,42 @@ func (tbl Table) Create(ctx context.Context, meta *bigquery.TableMetadata) error
8091
return nil
8192
}
8293

94+
// Update updates the table's `Schema`.
95+
func (tbl Table) Update(ctx context.Context, md bigquery.TableMetadataToUpdate, etag string) (*bigquery.TableMetadata, error) {
96+
if md.Schema != nil {
97+
tbl.metadata.Schema = md.Schema
98+
}
99+
return tbl.metadata, nil
100+
}
101+
83102
// Dataset implements part of the bqiface.Dataset interface.
84103
type Dataset struct {
85104
bqiface.Dataset
86-
tables map[string]*Table
105+
tables map[string]*Table
106+
metadata *bqiface.DatasetMetadata
107+
err error
108+
}
109+
110+
// NewDataset returns a new instance of Dataset.
111+
func NewDataset(t map[string]*Table, md *bqiface.DatasetMetadata, err error) *Dataset {
112+
return &Dataset{
113+
tables: t,
114+
metadata: md,
115+
err: err,
116+
}
117+
}
118+
119+
// Metadata implements the bqiface method.
120+
func (ds Dataset) Metadata(ctx context.Context) (*bqiface.DatasetMetadata, error) {
121+
if ds.metadata != nil {
122+
return ds.metadata, nil
123+
}
124+
return nil, errors.New("invalid dataset metadata")
125+
}
126+
127+
// Create returns an error.
128+
func (ds Dataset) Create(ctx context.Context, md *bqiface.DatasetMetadata) error {
129+
return ds.err
87130
}
88131

89132
// Table implements the bqiface method.

cloudtest/bqfake/bqfake_test.go

Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@ package bqfake_test
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"log"
78
"net/http"
89
"reflect"
910
"testing"
1011
"time"
1112

12-
"google.golang.org/api/option"
1313
"cloud.google.com/go/bigquery"
14+
"github.com/google/go-cmp/cmp"
1415
"github.com/googleapis/google-cloud-go-testing/bigquery/bqiface"
1516
"google.golang.org/api/iterator"
17+
"google.golang.org/api/option"
1618

1719
"github.com/m-lab/go/cloudtest/bqfake"
1820
)
@@ -55,7 +57,7 @@ func TestNewClientErr(t *testing.T) {
5557
ctx := context.Background()
5658
// These options are incompatible with one another and generate an error from bigquery.NewClient.
5759
opts := []option.ClientOption{option.WithAPIKey("asdf"), option.WithoutAuthentication()}
58-
c, err := bqfake.NewClient(ctx, "fakeProject", opts...)
60+
c, err := bqfake.NewClient(ctx, "fakeProject", map[string]*bqfake.Dataset{}, opts...)
5961
if err == nil {
6062
c.Close()
6163
t.Fatal("Should return constructing client error")
@@ -74,9 +76,82 @@ func TestBadDataset(t *testing.T) {
7476
ds.Table("Foobar")
7577
}
7678

79+
func TestDatasetMetadata(t *testing.T) {
80+
tests := []struct {
81+
name string
82+
md *bqiface.DatasetMetadata
83+
want *bqiface.DatasetMetadata
84+
wantErr bool
85+
}{
86+
{
87+
name: "success",
88+
md: &bqiface.DatasetMetadata{
89+
DatasetMetadata: bigquery.DatasetMetadata{
90+
Name: "fakeMetadata",
91+
},
92+
},
93+
want: &bqiface.DatasetMetadata{
94+
DatasetMetadata: bigquery.DatasetMetadata{
95+
Name: "fakeMetadata",
96+
},
97+
},
98+
wantErr: false,
99+
},
100+
{
101+
name: "error",
102+
md: nil,
103+
wantErr: true,
104+
},
105+
}
106+
107+
for _, tt := range tests {
108+
t.Run(tt.name, func(t *testing.T) {
109+
ds := bqfake.NewDataset(nil, tt.md, nil)
110+
got, err := ds.Metadata(context.Background())
111+
if (err != nil) != tt.wantErr {
112+
t.Errorf("Dataset.Metadata() error = %v, wantErr %v", err, tt.wantErr)
113+
return
114+
}
115+
116+
if !tt.wantErr && !cmp.Equal(got, tt.want) {
117+
t.Errorf("Dataset.Metadata() got = %v, want = %v", got, tt.want)
118+
}
119+
})
120+
}
121+
}
122+
123+
func TestDatasetCreate(t *testing.T) {
124+
tests := []struct {
125+
name string
126+
err error
127+
wantErr bool
128+
}{
129+
{
130+
name: "success",
131+
err: nil,
132+
wantErr: false,
133+
},
134+
{
135+
name: "error",
136+
err: errors.New("fakeError"),
137+
wantErr: true,
138+
},
139+
}
140+
141+
for _, tt := range tests {
142+
t.Run(tt.name, func(t *testing.T) {
143+
ds := bqfake.NewDataset(nil, nil, tt.err)
144+
got := ds.Create(context.Background(), &bqiface.DatasetMetadata{})
145+
if (got != nil) != tt.wantErr {
146+
t.Errorf("Dataset.Create() error = %v, wantErr %v", got, tt.wantErr)
147+
}
148+
})
149+
}
150+
}
151+
77152
func TestUninitializedTable(t *testing.T) {
78153
ctx := context.Background()
79-
c, err := bqfake.NewClient(ctx, "fakeProject")
154+
c, err := bqfake.NewClient(ctx, "fakeProject", map[string]*bqfake.Dataset{})
80155
if err != nil {
81156
t.Fatal(err)
82157
}
@@ -113,7 +188,7 @@ func TestUninitializedTable(t *testing.T) {
113188

114189
func TestTable(t *testing.T) {
115190
ctx := context.Background()
116-
c, err := bqfake.NewClient(ctx, "fakeProject")
191+
c, err := bqfake.NewClient(ctx, "fakeProject", map[string]*bqfake.Dataset{})
117192
if err != nil {
118193
t.Fatal(err)
119194
}
@@ -149,7 +224,7 @@ func createTable(ctx context.Context, ds bqiface.Dataset, name string) error {
149224

150225
func TestTableMetadata(t *testing.T) {
151226
ctx := context.Background()
152-
c, err := bqfake.NewClient(ctx, "fakeProject")
227+
c, err := bqfake.NewClient(ctx, "fakeProject", map[string]*bqfake.Dataset{})
153228
if err != nil {
154229
t.Fatal(err)
155230
}
@@ -179,9 +254,31 @@ func TestTableMetadata(t *testing.T) {
179254
}
180255
}
181256

257+
func TestTableUpdate(t *testing.T) {
258+
want := &bigquery.TableMetadata{
259+
Schema: []*bigquery.FieldSchema{
260+
{
261+
Name: "fakeField",
262+
},
263+
},
264+
}
265+
tbl := bqfake.NewTable(bqfake.Dataset{}, "", &bigquery.TableMetadata{}, nil)
266+
got, err := tbl.Update(context.Background(), bigquery.TableMetadataToUpdate{
267+
Schema: want.Schema,
268+
}, "")
269+
270+
if err != nil {
271+
t.Errorf("Table.Update() error = %v, wantErr = nil", err)
272+
}
273+
274+
if !cmp.Equal(got, want) {
275+
t.Errorf("Table.Update() got = %v, want = %v", got, want)
276+
}
277+
}
278+
182279
func TestQuery(t *testing.T) {
183280
ctx := context.Background()
184-
c, err := bqfake.NewClient(ctx, "fakeProject")
281+
c, err := bqfake.NewClient(ctx, "fakeProject", map[string]*bqfake.Dataset{})
185282
if err != nil {
186283
t.Fatal(err)
187284
}

cloudtest/bqfake/client.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,26 +68,32 @@ func DryRunClient() (*http.Client, *CountingTransport) {
6868
// Client implements a fake client.
6969
type Client struct {
7070
bqiface.Client
71-
ctx context.Context // Just for checking expiration/cancelation
72-
config ClientConfig
71+
ctx context.Context // Just for checking expiration/cancelation
72+
datasets map[string]*Dataset
73+
config ClientConfig
7374
}
7475

7576
// NewClient creates a new Client implementing bqiface.Client, with a dry run HTTPClient.
76-
func NewClient(ctx context.Context, project string, opts ...option.ClientOption) (*Client, error) {
77+
func NewClient(ctx context.Context, project string, ds map[string]*Dataset, opts ...option.ClientOption) (*Client, error) {
7778
dryRun, _ := DryRunClient()
7879
opts = append(opts, option.WithHTTPClient(dryRun))
7980
c, err := bigquery.NewClient(ctx, project, opts...)
8081
if err != nil {
8182
return nil, err
8283
}
83-
return &Client{Client: bqiface.AdaptClient(c), ctx: ctx}, nil
84+
return &Client{Client: bqiface.AdaptClient(c), ctx: ctx, datasets: ds}, nil
8485
}
8586

8687
// Dataset creates a Dataset.
8788
// TODO - understand how bqiface adapters/structs work, and make this return a Dataset
8889
// that satisfies bqiface.Dataset interface?
89-
func (client Client) Dataset(ds string) bqiface.Dataset {
90-
return Dataset{Dataset: client.Client.Dataset(ds), tables: make(map[string]*Table)}
90+
func (client Client) Dataset(name string) bqiface.Dataset {
91+
ds, ok := client.datasets[name]
92+
if !ok {
93+
ds = &Dataset{Dataset: client.Client.Dataset(name), tables: make(map[string]*Table)}
94+
client.datasets[name] = ds
95+
}
96+
return ds
9197
}
9298

9399
func (client Client) Query(string) bqiface.Query {

0 commit comments

Comments
 (0)