From 1499ec283673dca14fa37a4860e8fe6e9daccc03 Mon Sep 17 00:00:00 2001 From: Sriharsha Tikkireddy Date: Sun, 19 Apr 2020 20:43:39 -0400 Subject: [PATCH] Added unit test coverage for notebooks. Added better error logic for fetching recursive paths. Errors will fail the recursive call. --- client/service/notebooks.go | 20 +- client/service/notebooks_test.go | 386 +++++++++++++++++++++++++++++++ 2 files changed, 401 insertions(+), 5 deletions(-) create mode 100644 client/service/notebooks_test.go diff --git a/client/service/notebooks.go b/client/service/notebooks.go index dd683ed1d..c38f5087f 100644 --- a/client/service/notebooks.go +++ b/client/service/notebooks.go @@ -75,22 +75,32 @@ func (a NotebooksAPI) Mkdirs(path string) error { func (a NotebooksAPI) List(path string, recursive bool) ([]model.NotebookInfo, error) { if recursive == true { var paths []model.NotebookInfo - a.recursiveAddPaths(path, &paths) - return paths, nil + err := a.recursiveAddPaths(path, &paths) + if err != nil { + return nil, err + } + return paths, err } else { return a.list(path) } } -func (a NotebooksAPI) recursiveAddPaths(path string, pathList *[]model.NotebookInfo) { - notebookInfoList, _ := a.list(path) +func (a NotebooksAPI) recursiveAddPaths(path string, pathList *[]model.NotebookInfo) error { + notebookInfoList, err := a.list(path) + if err != nil { + return err + } for _, v := range notebookInfoList { if v.ObjectType == model.Notebook { *pathList = append(*pathList, v) } else if v.ObjectType == model.Directory { - a.recursiveAddPaths(v.Path, pathList) + err := a.recursiveAddPaths(v.Path, pathList) + if err != nil { + return err + } } } + return err } func (a NotebooksAPI) list(path string) ([]model.NotebookInfo, error) { diff --git a/client/service/notebooks_test.go b/client/service/notebooks_test.go new file mode 100644 index 000000000..ba498ceaa --- /dev/null +++ b/client/service/notebooks_test.go @@ -0,0 +1,386 @@ +package service + +import ( + "github.com/databrickslabs/databricks-terraform/client/model" + "net/http" + "testing" +) + +func TestNotebooksAPI_Create(t *testing.T) { + type args struct { + Content string `json:"content,omitempty"` + Path string `json:"path,omitempty"` + Language model.Language `json:"language,omitempty"` + Overwrite bool `json:"overwrite,omitempty"` + Format model.ExportFormat `json:"format,omitempty"` + } + + tests := []struct { + name string + response string + args args + wantErr bool + }{ + { + name: "Create Test", + response: "", + args: args{ + Content: "helloworld", + Path: "my-path", + Language: model.Python, + Overwrite: false, + Format: model.DBC, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var input args + AssertRequestWithMockServer(t, &tt.args, http.MethodPost, "/api/2.0/workspace/import", &input, tt.response, http.StatusOK, nil, tt.wantErr, func(client DBApiClient) (interface{}, error) { + return nil, client.Notebooks().Create(tt.args.Path, tt.args.Content, tt.args.Language, tt.args.Format, tt.args.Overwrite) + }) + }) + } +} + +func TestNotebooksAPI_MkDirs(t *testing.T) { + type args struct { + Path string `json:"path,omitempty"` + } + + tests := []struct { + name string + response string + args args + wantErr bool + }{ + { + name: "Create Test", + response: "", + args: args{ + Path: "/test/path", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var input args + AssertRequestWithMockServer(t, &tt.args, http.MethodPost, "/api/2.0/workspace/mkdirs", &input, tt.response, http.StatusOK, nil, tt.wantErr, func(client DBApiClient) (interface{}, error) { + return nil, client.Notebooks().Mkdirs(tt.args.Path) + }) + }) + } +} + +func TestNotebooksAPI_Delete(t *testing.T) { + type args struct { + Path string `json:"path,omitempty"` + Recursive bool `json:"recursive,omitempty"` + } + tests := []struct { + name string + response string + responseStatus int + args args + wantErr bool + }{ + { + name: "Delete test", + response: "", + responseStatus: http.StatusOK, + args: args{ + Path: "mypath", + Recursive: false, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var input args + AssertRequestWithMockServer(t, &tt.args, http.MethodPost, "/api/2.0/workspace/delete", &input, tt.response, tt.responseStatus, nil, tt.wantErr, func(client DBApiClient) (interface{}, error) { + return nil, client.Notebooks().Delete(tt.args.Path, tt.args.Recursive) + }) + }) + } +} + +func TestNotebooksAPI_ListNonRecursive(t *testing.T) { + type args struct { + Path string `json:"path"` + Recursive bool `json:"recursive"` + } + tests := []struct { + name string + response string + responseStatus int + args args + wantUri string + want []model.NotebookInfo + wantErr bool + }{ + { + name: "List non recursive test", + response: `{ + "objects": [ + { + "path": "/Users/user@example.com/project", + "object_type": "DIRECTORY", + "object_id": 123 + }, + { + "path": "/Users/user@example.com/PythonExampleNotebook", + "language": "PYTHON", + "object_type": "NOTEBOOK", + "object_id": 456 + } + ] + }`, + responseStatus: http.StatusOK, + args: args{ + + Path: "/test/path", + Recursive: false, + }, + wantUri: "/api/2.0/workspace/list?path=%2Ftest%2Fpath", + want: []model.NotebookInfo{ + { + ObjectId: 123, + ObjectType: model.Directory, + Path: "/Users/user@example.com/project", + }, + { + ObjectId: 456, + ObjectType: model.Notebook, + Language: model.Python, + Path: "/Users/user@example.com/PythonExampleNotebook", + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var input args + AssertRequestWithMockServer(t, tt.args, http.MethodGet, tt.wantUri, &input, tt.response, tt.responseStatus, tt.want, tt.wantErr, func(client DBApiClient) (interface{}, error) { + return client.Notebooks().List(tt.args.Path, tt.args.Recursive) + }) + }) + } +} + +func TestNotebooksAPI_ListRecursive(t *testing.T) { + type args struct { + Path string `json:"path"` + Recursive bool `json:"recursive"` + } + tests := []struct { + name string + response []string + responseStatus []int + args []interface{} + wantUri []string + want []model.NotebookInfo + wantErr bool + }{ + { + name: "List recursive test", + response: []string{`{ + "objects": [ + { + "path": "/Users/user@example.com/project", + "object_type": "DIRECTORY", + "object_id": 123 + }, + { + "path": "/Users/user@example.com/PythonExampleNotebook", + "language": "PYTHON", + "object_type": "NOTEBOOK", + "object_id": 456 + } + ] + }`, + `{ + "objects": [ + { + "path": "/Users/user@example.com/Notebook2", + "language": "PYTHON", + "object_type": "NOTEBOOK", + "object_id": 457 + } + ] + }`, + }, + responseStatus: []int{http.StatusOK, http.StatusOK}, + args: []interface{}{ + &args{ + Path: "/test/path", + Recursive: true, + }, + }, + wantUri: []string{"/api/2.0/workspace/list?path=%2Ftest%2Fpath", "/api/2.0/workspace/list?path=%2FUsers%2Fuser%40example.com%2Fproject"}, + want: []model.NotebookInfo{ + { + ObjectId: 457, + ObjectType: model.Notebook, + Language: model.Python, + Path: "/Users/user@example.com/Notebook2", + }, + { + ObjectId: 456, + ObjectType: model.Notebook, + Language: model.Python, + Path: "/Users/user@example.com/PythonExampleNotebook", + }, + }, + wantErr: false, + }, + { + name: "List recursive test failure", + response: []string{`{ + "objects": [ + { + "path": "/Users/user@example.com/project", + "object_type": "DIRECTORY", + "object_id": 123 + }, + { + "path": "/Users/user@example.com/PythonExampleNotebook", + "language": "PYTHON", + "object_type": "NOTEBOOK", + "object_id": 456 + } + ] + }`, + ``, + }, + responseStatus: []int{http.StatusOK, http.StatusBadRequest}, + args: []interface{}{ + &args{ + Path: "/test/path", + Recursive: true, + }, + }, + wantUri: []string{"/api/2.0/workspace/list?path=%2Ftest%2Fpath", "/api/2.0/workspace/list?path=%2FUsers%2Fuser%40example.com%2Fproject"}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + AssertMultipleRequestsWithMockServer(t, tt.args, []string{http.MethodGet, http.MethodGet}, tt.wantUri, []interface{}{&args{}}, tt.response, tt.responseStatus, tt.want, tt.wantErr, func(client DBApiClient) (interface{}, error) { + return client.Notebooks().List(tt.args[0].(*args).Path, tt.args[0].(*args).Recursive) + }) + }) + } +} + +func TestNotebooksAPI_Read(t *testing.T) { + type args struct { + Path string `json:"path"` + } + tests := []struct { + name string + response string + args args + responseStatus int + wantUri string + want model.NotebookInfo + wantErr bool + }{ + { + name: "Read test", + response: `{ + "path": "/Users/user@example.com/project/ScalaExampleNotebook", + "language": "SCALA", + "object_type": "NOTEBOOK", + "object_id": 789 + }`, + args: args{ + Path: "/test/path", + }, + responseStatus: http.StatusOK, + want: model.NotebookInfo{ + ObjectId: 789, + ObjectType: model.Notebook, + Path: "/Users/user@example.com/project/ScalaExampleNotebook", + Language: model.Scala, + }, + wantUri: "/api/2.0/workspace/get-status?path=%2Ftest%2Fpath", + wantErr: false, + }, + + { + name: "Read test failure", + response: ``, + args: args{ + Path: "/test/path", + }, + responseStatus: http.StatusBadRequest, + want: model.NotebookInfo{}, + wantUri: "/api/2.0/workspace/get-status?path=%2Ftest%2Fpath", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var input args + AssertRequestWithMockServer(t, &tt.args, http.MethodGet, tt.wantUri, &input, tt.response, tt.responseStatus, tt.want, tt.wantErr, func(client DBApiClient) (interface{}, error) { + return client.Notebooks().Read(tt.args.Path) + }) + }) + } +} + +func TestNotebooksAPI_Export(t *testing.T) { + type args struct { + Path string `json:"path"` + Format model.ExportFormat `json:"format"` + } + tests := []struct { + name string + response string + args args + responseStatus int + wantUri string + want string + wantErr bool + }{ + { + name: "Export test", + response: `{ + "content": "Ly8gRGF0YWJyaWNrcyBub3RlYm9vayBzb3VyY2UKMSsx" + }`, + args: args{ + Path: "/test/path", + Format: model.DBC, + }, + responseStatus: http.StatusOK, + want: "Ly8gRGF0YWJyaWNrcyBub3RlYm9vayBzb3VyY2UKMSsx", + wantUri: "/api/2.0/workspace/export?format=DBC&path=%2Ftest%2Fpath", + wantErr: false, + }, + { + name: "Export test failure", + response: ``, + args: args{ + Path: "/test/path", + Format: model.DBC, + }, + responseStatus: http.StatusBadRequest, + want: "", + wantUri: "/api/2.0/workspace/export?format=DBC&path=%2Ftest%2Fpath", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var input args + AssertRequestWithMockServer(t, &tt.args, http.MethodGet, tt.wantUri, &input, tt.response, tt.responseStatus, tt.want, tt.wantErr, func(client DBApiClient) (interface{}, error) { + return client.Notebooks().Export(tt.args.Path, tt.args.Format) + }) + }) + } +}