...

Source file src/cloud.google.com/go/bigquery/routine_test.go

Documentation: cloud.google.com/go/bigquery

     1  // Copyright 2019 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  
    16  import (
    17  	"fmt"
    18  	"testing"
    19  	"time"
    20  
    21  	"cloud.google.com/go/internal/testutil"
    22  	bq "google.golang.org/api/bigquery/v2"
    23  )
    24  
    25  func testRoutineConversion(t *testing.T, conversion string, in interface{}, want interface{}) {
    26  	var got interface{}
    27  	var err error
    28  	switch conversion {
    29  	case "ToRoutineMetadata":
    30  		input, ok := in.(*bq.Routine)
    31  		if !ok {
    32  			t.Fatalf("failed input type conversion (bq.Routine): %v", in)
    33  		}
    34  		got, err = bqToRoutineMetadata(input)
    35  	case "FromRoutineMetadata":
    36  		input, ok := in.(*RoutineMetadata)
    37  		if !ok {
    38  			t.Fatalf("failed input type conversion (bq.RoutineMetadata): %v", in)
    39  		}
    40  		got, err = input.toBQ()
    41  	case "FromRoutineMetadataToUpdate":
    42  		input, ok := in.(*RoutineMetadataToUpdate)
    43  		if !ok {
    44  			t.Fatalf("failed input type conversion: %v", in)
    45  		}
    46  		got, err = input.toBQ()
    47  	case "ToRoutineArgument":
    48  		input, ok := in.(*bq.Argument)
    49  		if !ok {
    50  			t.Fatalf("failed input type conversion: %v", in)
    51  		}
    52  		got, err = bqToRoutineArgument(input)
    53  	case "FromRoutineArgument":
    54  		input, ok := in.(*RoutineArgument)
    55  		if !ok {
    56  			t.Fatalf("failed input type conversion: %v", in)
    57  		}
    58  		got, err = input.toBQ()
    59  	default:
    60  		t.Fatalf("invalid comparison: %s", conversion)
    61  	}
    62  	if err != nil {
    63  		t.Fatalf("failed conversion function for %q: %v", conversion, err)
    64  	}
    65  	if diff := testutil.Diff(got, want); diff != "" {
    66  		t.Fatalf("%+v: -got, +want:\n%s", in, diff)
    67  	}
    68  }
    69  
    70  func TestRoutineTypeConversions(t *testing.T) {
    71  	aTime := time.Date(2019, 3, 14, 0, 0, 0, 0, time.Local)
    72  	aTimeMillis := aTime.UnixNano() / 1e6
    73  
    74  	tests := []struct {
    75  		name       string
    76  		conversion string
    77  		in         interface{}
    78  		want       interface{}
    79  	}{
    80  		{
    81  			name:       "empty",
    82  			conversion: "ToRoutineMetadata",
    83  			in:         &bq.Routine{},
    84  			want:       &RoutineMetadata{},
    85  		},
    86  		{
    87  			name:       "empty",
    88  			conversion: "FromRoutineMetadata",
    89  			in:         &RoutineMetadata{},
    90  			want:       &bq.Routine{},
    91  		},
    92  		{
    93  			name:       "basic",
    94  			conversion: "ToRoutineMetadata",
    95  			in: &bq.Routine{
    96  				CreationTime:     aTimeMillis,
    97  				LastModifiedTime: aTimeMillis,
    98  				DefinitionBody:   "body",
    99  				Description:      "desc",
   100  				Etag:             "etag",
   101  				DeterminismLevel: "DETERMINISTIC",
   102  				RoutineType:      "type",
   103  				Language:         "lang",
   104  				ReturnType:       &bq.StandardSqlDataType{TypeKind: "INT64"},
   105  				ReturnTableType: &bq.StandardSqlTableType{
   106  					Columns: []*bq.StandardSqlField{
   107  						{Name: "field", Type: &bq.StandardSqlDataType{TypeKind: "FLOAT64"}},
   108  					},
   109  				},
   110  				DataGovernanceType: "DATA_MASKING",
   111  			},
   112  			want: &RoutineMetadata{
   113  				CreationTime:     aTime,
   114  				LastModifiedTime: aTime,
   115  				Description:      "desc",
   116  				DeterminismLevel: Deterministic,
   117  				Body:             "body",
   118  				ETag:             "etag",
   119  				Type:             "type",
   120  				Language:         "lang",
   121  				ReturnType:       &StandardSQLDataType{TypeKind: "INT64"},
   122  				ReturnTableType: &StandardSQLTableType{
   123  					Columns: []*StandardSQLField{
   124  						{Name: "field", Type: &StandardSQLDataType{TypeKind: "FLOAT64"}},
   125  					},
   126  				},
   127  				DataGovernanceType: "DATA_MASKING",
   128  			},
   129  		},
   130  		{
   131  			name:       "basic",
   132  			conversion: "FromRoutineMetadata",
   133  			in: &RoutineMetadata{
   134  				Description:      "desc",
   135  				DeterminismLevel: Deterministic,
   136  				Body:             "body",
   137  				Type:             "type",
   138  				Language:         "lang",
   139  				ReturnType:       &StandardSQLDataType{TypeKind: "INT64"},
   140  				ReturnTableType: &StandardSQLTableType{
   141  					Columns: []*StandardSQLField{
   142  						{Name: "field", Type: &StandardSQLDataType{TypeKind: "FLOAT64"}},
   143  					},
   144  				},
   145  				DataGovernanceType: "DATA_MASKING",
   146  			},
   147  			want: &bq.Routine{
   148  				DefinitionBody:   "body",
   149  				Description:      "desc",
   150  				DeterminismLevel: "DETERMINISTIC",
   151  				RoutineType:      "type",
   152  				Language:         "lang",
   153  				ReturnType:       &bq.StandardSqlDataType{TypeKind: "INT64"},
   154  				ReturnTableType: &bq.StandardSqlTableType{
   155  					Columns: []*bq.StandardSqlField{
   156  						{Name: "field", Type: &bq.StandardSqlDataType{TypeKind: "FLOAT64"}},
   157  					},
   158  				},
   159  				DataGovernanceType: "DATA_MASKING",
   160  			},
   161  		},
   162  		{
   163  			name:       "body_and_libs",
   164  			conversion: "FromRoutineMetadataToUpdate",
   165  			in: &RoutineMetadataToUpdate{
   166  				Body:               "body",
   167  				ImportedLibraries:  []string{"foo", "bar"},
   168  				ReturnType:         &StandardSQLDataType{TypeKind: "FOO"},
   169  				DataGovernanceType: "DATA_MASKING",
   170  			},
   171  			want: &bq.Routine{
   172  				DefinitionBody:     "body",
   173  				ImportedLibraries:  []string{"foo", "bar"},
   174  				ReturnType:         &bq.StandardSqlDataType{TypeKind: "FOO"},
   175  				DataGovernanceType: "DATA_MASKING",
   176  				ForceSendFields:    []string{"DefinitionBody", "ImportedLibraries", "ReturnType", "DataGovernanceType"},
   177  			},
   178  		},
   179  		{
   180  			name:       "null_fields",
   181  			conversion: "FromRoutineMetadataToUpdate",
   182  			in: &RoutineMetadataToUpdate{
   183  				Type:              "type",
   184  				Arguments:         []*RoutineArgument{},
   185  				ImportedLibraries: []string{},
   186  			},
   187  			want: &bq.Routine{
   188  				RoutineType:     "type",
   189  				ForceSendFields: []string{"RoutineType"},
   190  				NullFields:      []string{"Arguments", "ImportedLibraries"},
   191  			},
   192  		},
   193  		{
   194  			name:       "empty",
   195  			conversion: "ToRoutineArgument",
   196  			in:         &bq.Argument{},
   197  			want:       &RoutineArgument{}},
   198  		{
   199  			name:       "basic",
   200  			conversion: "ToRoutineArgument",
   201  			in: &bq.Argument{
   202  				Name:         "foo",
   203  				ArgumentKind: "bar",
   204  				Mode:         "baz",
   205  			},
   206  			want: &RoutineArgument{
   207  				Name: "foo",
   208  				Kind: "bar",
   209  				Mode: "baz",
   210  			},
   211  		},
   212  		{
   213  			name:       "empty",
   214  			conversion: "FromRoutineArgument",
   215  			in:         &RoutineArgument{},
   216  			want:       &bq.Argument{},
   217  		},
   218  		{
   219  			name:       "basic",
   220  			conversion: "FromRoutineArgument",
   221  			in: &RoutineArgument{
   222  				Name: "foo",
   223  				Kind: "bar",
   224  				Mode: "baz",
   225  			},
   226  			want: &bq.Argument{
   227  				Name:         "foo",
   228  				ArgumentKind: "bar",
   229  				Mode:         "baz",
   230  			}},
   231  	}
   232  
   233  	for _, test := range tests {
   234  		t.Run(fmt.Sprintf("%s/%s", test.conversion, test.name), func(t *testing.T) {
   235  			testRoutineConversion(t, test.conversion, test.in, test.want)
   236  		})
   237  	}
   238  }
   239  
   240  func TestRoutineIdentifiers(t *testing.T) {
   241  	testRoutine := &Routine{
   242  		ProjectID: "p",
   243  		DatasetID: "d",
   244  		RoutineID: "r",
   245  		c:         nil,
   246  	}
   247  	for _, tc := range []struct {
   248  		description string
   249  		in          *Routine
   250  		format      IdentifierFormat
   251  		want        string
   252  		wantErr     bool
   253  	}{
   254  		{
   255  			description: "empty format string",
   256  			in:          testRoutine,
   257  			format:      "",
   258  			wantErr:     true,
   259  		},
   260  		{
   261  			description: "legacy",
   262  			in:          testRoutine,
   263  			wantErr:     true,
   264  		},
   265  		{
   266  			description: "standard unquoted",
   267  			in:          testRoutine,
   268  			format:      StandardSQLID,
   269  			want:        "p.d.r",
   270  		},
   271  		{
   272  			description: "standard w/dash",
   273  			in:          &Routine{ProjectID: "p-p", DatasetID: "d", RoutineID: "r"},
   274  			format:      StandardSQLID,
   275  			want:        "`p-p`.d.r",
   276  		},
   277  		{
   278  			description: "api resource",
   279  			in:          testRoutine,
   280  			format:      StorageAPIResourceID,
   281  			wantErr:     true,
   282  		},
   283  	} {
   284  		got, err := tc.in.Identifier(tc.format)
   285  		if tc.wantErr && err == nil {
   286  			t.Errorf("case %q: wanted err, was success", tc.description)
   287  		}
   288  		if !tc.wantErr {
   289  			if err != nil {
   290  				t.Errorf("case %q: wanted success, got err: %v", tc.description, err)
   291  			} else {
   292  				if got != tc.want {
   293  					t.Errorf("case %q:  got %s, want %s", tc.description, got, tc.want)
   294  				}
   295  			}
   296  		}
   297  	}
   298  }
   299  

View as plain text