blob: 8cf6446a3b3fecc1eb6ce981515d6995a9a190c3 [file] [edit]
// Copyright 2017 Google LLC
//
// 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 (
"reflect"
"testing"
"time"
"cloud.google.com/go/internal/testutil"
bq "google.golang.org/api/bigquery/v2"
)
func TestCreateJobRef(t *testing.T) {
defer fixRandomID("RANDOM")()
cNoLoc := &Client{projectID: "projectID"}
cLoc := &Client{projectID: "projectID", Location: "defaultLoc"}
for _, test := range []struct {
in JobIDConfig
client *Client
want *bq.JobReference
}{
{
in: JobIDConfig{JobID: "foo"},
want: &bq.JobReference{JobId: "foo"},
},
{
in: JobIDConfig{},
want: &bq.JobReference{JobId: "RANDOM"},
},
{
in: JobIDConfig{AddJobIDSuffix: true},
want: &bq.JobReference{JobId: "RANDOM"},
},
{
in: JobIDConfig{JobID: "foo", AddJobIDSuffix: true},
want: &bq.JobReference{JobId: "foo-RANDOM"},
},
{
in: JobIDConfig{JobID: "foo", Location: "loc"},
want: &bq.JobReference{JobId: "foo", Location: "loc"},
},
{
in: JobIDConfig{JobID: "foo"},
client: cLoc,
want: &bq.JobReference{JobId: "foo", Location: "defaultLoc"},
},
{
in: JobIDConfig{JobID: "foo", Location: "loc"},
client: cLoc,
want: &bq.JobReference{JobId: "foo", Location: "loc"},
},
{
in: JobIDConfig{JobID: "foo", ProjectID: "anotherProj"},
want: &bq.JobReference{JobId: "foo", ProjectId: "anotherProj"},
},
} {
client := test.client
if client == nil {
client = cNoLoc
}
got := test.in.createJobRef(client)
if test.want.ProjectId == "" {
test.want.ProjectId = "projectID"
}
if !testutil.Equal(got, test.want) {
t.Errorf("%+v: got %+v, want %+v", test.in, got, test.want)
}
}
}
// Ideally this would be covered by an integration test but simulating
// performance issues in a dummy project is difficult and requires a lot of set
// up.
func Test_JobPerformanceInsights(t *testing.T) {
for _, test := range []struct {
name string
in *bq.PerformanceInsights
want *PerformanceInsights
}{
{
name: "nil",
},
{
name: "time only",
in: &bq.PerformanceInsights{AvgPreviousExecutionMs: 128},
want: &PerformanceInsights{AvgPreviousExecution: 128 * time.Millisecond},
},
{
name: "full",
in: &bq.PerformanceInsights{
AvgPreviousExecutionMs: 128,
StagePerformanceChangeInsights: []*bq.StagePerformanceChangeInsight{
{InputDataChange: &bq.InputDataChange{RecordsReadDiffPercentage: 1.23}, StageId: 123},
{InputDataChange: &bq.InputDataChange{RecordsReadDiffPercentage: 4.56}, StageId: 456},
},
StagePerformanceStandaloneInsights: []*bq.StagePerformanceStandaloneInsight{
{
BiEngineReasons: []*bq.BiEngineReason{
{Code: "bi-code-1", Message: "bi-message-1"},
},
HighCardinalityJoins: []*bq.HighCardinalityJoin{
{LeftRows: 11, OutputRows: 22, RightRows: 33, StepIndex: 112233},
{LeftRows: 44, OutputRows: 55, RightRows: 66, StepIndex: 445566},
},
InsufficientShuffleQuota: true,
PartitionSkew: &bq.PartitionSkew{SkewSources: []*bq.SkewSource{
{StageId: 321},
{StageId: 654},
}},
StageId: 123456,
},
{
BiEngineReasons: []*bq.BiEngineReason{
{Code: "bi-code-2", Message: "bi-message-2"},
{Code: "bi-code-3", Message: "bi-message-3"},
},
HighCardinalityJoins: []*bq.HighCardinalityJoin{
{LeftRows: 77, OutputRows: 88, RightRows: 99, StepIndex: 778899},
},
PartitionSkew: &bq.PartitionSkew{SkewSources: []*bq.SkewSource{{StageId: 987}}},
SlotContention: true,
StageId: 654321,
},
},
},
want: &PerformanceInsights{
AvgPreviousExecution: 128 * time.Millisecond,
StagePerformanceChangeInsights: []*StagePerformanceChangeInsight{
{InputDataChange: &InputDataChange{RecordsReadDiffPercentage: 1.23}, StageID: 123},
{InputDataChange: &InputDataChange{RecordsReadDiffPercentage: 4.56}, StageID: 456},
},
StagePerformanceStandaloneInsights: []*StagePerformanceStandaloneInsight{
{
BIEngineReasons: []*BIEngineReason{
{Code: "bi-code-1", Message: "bi-message-1"},
},
HighCardinalityJoins: []*HighCardinalityJoin{
{LeftRows: 11, OutputRows: 22, RightRows: 33, StepIndex: 112233},
{LeftRows: 44, OutputRows: 55, RightRows: 66, StepIndex: 445566},
},
InsufficientShuffleQuota: true,
PartitionSkew: &PartitionSkew{SkewSources: []*SkewSource{{StageID: 321}, {StageID: 654}}},
StageID: 123456,
},
{
BIEngineReasons: []*BIEngineReason{
{Code: "bi-code-2", Message: "bi-message-2"},
{Code: "bi-code-3", Message: "bi-message-3"},
},
HighCardinalityJoins: []*HighCardinalityJoin{
{LeftRows: 77, OutputRows: 88, RightRows: 99, StepIndex: 778899},
},
PartitionSkew: &PartitionSkew{SkewSources: []*SkewSource{{StageID: 987}}},
SlotContention: true,
StageID: 654321,
},
},
},
},
} {
t.Run(test.name, func(t *testing.T) {
out := bqToPerformanceInsights(test.in)
if !reflect.DeepEqual(test.want, out) {
t.Error("out != want")
}
})
}
}
func fixRandomID(s string) func() {
prev := randomIDFn
randomIDFn = func() string { return s }
return func() { randomIDFn = prev }
}
func checkJob(t *testing.T, i int, got, want *bq.Job) {
if got.JobReference == nil {
t.Errorf("#%d: empty job reference", i)
return
}
if got.JobReference.JobId == "" {
t.Errorf("#%d: empty job ID", i)
return
}
d := testutil.Diff(got, want)
if d != "" {
t.Errorf("#%d: (got=-, want=+) %s", i, d)
}
}