diff --git a/internal/metadata/project.go b/internal/metadata/project.go index cecca2578..0213eba8a 100644 --- a/internal/metadata/project.go +++ b/internal/metadata/project.go @@ -3,10 +3,16 @@ package metadata import ( "context" "database/sql" + "errors" "fmt" "sync" ) +var ( + ErrDuplicatedDataset = errors.New("dataset is already created") + ErrDuplicatedJob = errors.New("job is already created") +) + type Project struct { ID string datasets []*Dataset @@ -69,7 +75,7 @@ func (p *Project) AddDataset(ctx context.Context, tx *sql.Tx, dataset *Dataset) p.mu.Lock() defer p.mu.Unlock() if _, exists := p.datasetMap[dataset.ID]; exists { - return fmt.Errorf("dataset %s is already created", dataset.ID) + return fmt.Errorf("dataset %s: %w", dataset.ID, ErrDuplicatedDataset) } if err := dataset.Insert(ctx, tx); err != nil { return err @@ -111,7 +117,7 @@ func (p *Project) AddJob(ctx context.Context, tx *sql.Tx, job *Job) error { p.mu.Lock() defer p.mu.Unlock() if _, exists := p.jobMap[job.ID]; exists { - return fmt.Errorf("job %s is already created", job.ID) + return fmt.Errorf("job %s: %w", job.ID, ErrDuplicatedJob) } if err := job.Insert(ctx, tx); err != nil { return err diff --git a/server/handler.go b/server/handler.go index 7a5d2c0b7..8e6f53272 100644 --- a/server/handler.go +++ b/server/handler.go @@ -681,7 +681,11 @@ func (h *datasetsInsertHandler) ServeHTTP(w http.ResponseWriter, r *http.Request dataset: &dataset, }) if err != nil { - errorResponse(ctx, w, errInternalError(err.Error())) + if errors.Is(err, metadata.ErrDuplicatedDataset) { + errorResponse(ctx, w, errDuplicate(err.Error())) + } else { + errorResponse(ctx, w, errInternalError(err.Error())) + } return } encodeResponse(ctx, w, res) @@ -1016,7 +1020,11 @@ func (h *jobsInsertHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { job: &job, }) if err != nil { - errorResponse(ctx, w, errJobInternalError(err.Error())) + if errors.Is(err, metadata.ErrDuplicatedJob) { + errorResponse(ctx, w, errDuplicate(err.Error())) + } else { + errorResponse(ctx, w, errJobInternalError(err.Error())) + } return } encodeResponse(ctx, w, res) diff --git a/server/server_test.go b/server/server_test.go index a27f49208..e1bb89443 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -867,6 +867,58 @@ func TestDuplicateTable(t *testing.T) { } } +func TestDuplicateDataset(t *testing.T) { + const ( + projectName = "test" + datasetName = "dataset1" + ) + + ctx := context.Background() + + bqServer, err := server.New(server.TempStorage) + if err != nil { + t.Fatal(err) + } + if err := bqServer.SetProject(projectName); err != nil { + t.Fatal(err) + } + + testServer := bqServer.TestServer() + defer func() { + testServer.Close() + bqServer.Stop(ctx) + }() + + client, err := bigquery.NewClient( + ctx, + projectName, + option.WithEndpoint(testServer.URL), + option.WithoutAuthentication(), + ) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + dataset := client.Dataset(datasetName) + if err := dataset.Create(ctx, &bigquery.DatasetMetadata{ + Name: datasetName, + }); err != nil { + t.Fatalf("%+v", err) + } + + if err := dataset.Create(ctx, &bigquery.DatasetMetadata{ + Name: datasetName, + }); err != nil { + ge := err.(*googleapi.Error) + if ge.Code != 409 { + t.Fatalf("expected 409 Conflict, got %d: %+v", ge.Code, ge) + } + } else { + t.Fatal("expected error when dataset name duplicates") + } +} + func TestDuplicateTableWithSchema(t *testing.T) { const ( projectName = "test"