Skip to content

Commit 5a14007

Browse files
[DO NOT MERGE] Display only attachable clusters (#116)
Fixes #21 Wait for #118 (adds Permissions API) to merge https://user-images.githubusercontent.com/88345179/194365639-36dc4f38-4f6b-4d3d-9e9d-d2c88327d971.mov
1 parent 2633091 commit 5a14007

10 files changed

Lines changed: 563 additions & 205 deletions

packages/databricks-vscode/src/cluster/ClusterListDataProvider.test.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ describe(__filename, () => {
4545
};
4646
});
4747
let apiClient = instance(mock(ApiClient));
48-
when(mockedClusterModel.roots).thenResolve(
48+
when(mockedClusterModel.roots).thenReturn(
4949
mockListClustersResponse.clusters!.map(
5050
(m: any) => new Cluster(apiClient, m)
5151
)
@@ -99,20 +99,6 @@ describe(__filename, () => {
9999
assert.equal(children.length, 4);
100100
});
101101

102-
it("should return placeholder if list is empty", async () => {
103-
when(mockedClusterModel.roots).thenResolve([]);
104-
105-
let model = instance(mockedClusterModel);
106-
let provider = new ClusterListDataProvider(model);
107-
disposables.push(provider);
108-
109-
let children = await resolveProviderResult(provider.getChildren());
110-
assert(children);
111-
assert.equal(children.length, 1);
112-
assert(children[0] instanceof TreeItem);
113-
assert.equal(children[0].label, "No clusters found");
114-
});
115-
116102
it("should get cluster tree node items", () => {
117103
let cluster = new Cluster(
118104
instance(mock(ApiClient)),

packages/databricks-vscode/src/cluster/ClusterListDataProvider.ts

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ export class ClusterListDataProvider
3030
model.onDidChange(() => {
3131
this._onDidChangeTreeData.fire();
3232
}),
33-
this.autoReload(15000),
3433
];
34+
this.model.refresh();
3535
}
3636

3737
dispose() {
@@ -54,17 +54,6 @@ export class ClusterListDataProvider
5454
return (element as Cluster).state !== undefined;
5555
}
5656

57-
private autoReload(refreshRateInMs: number): Disposable {
58-
let interval = setInterval(() => {
59-
this.model.refresh();
60-
}, refreshRateInMs);
61-
return {
62-
dispose() {
63-
clearInterval(interval);
64-
},
65-
};
66-
}
67-
6857
getChildren(
6958
element?: Cluster | TreeItem | undefined
7059
): ProviderResult<Array<Cluster | TreeItem>> {
@@ -75,13 +64,8 @@ export class ClusterListDataProvider
7564
return [];
7665
}
7766
} else {
78-
return (async () => {
79-
let roots = await this.model.roots;
80-
if (roots && roots.length === 0) {
81-
return [new TreeItem("No clusters found")];
82-
} else {
83-
return roots;
84-
}
67+
return (() => {
68+
return this.model.roots;
8569
})();
8670
}
8771
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
2+
import {ApiClient, cluster, permissions} from "@databricks/databricks-sdk";
3+
import {ScimMeResponse} from "@databricks/databricks-sdk/dist/apis/scim";
4+
import assert from "assert";
5+
import {anyString, anything, instance, mock, spy, when} from "ts-mockito";
6+
import {ConnectionManager} from "../configuration/ConnectionManager";
7+
import {ClusterLoader} from "./ClusterLoader";
8+
9+
const me: ScimMeResponse = {
10+
entitlements: [],
11+
groups: [
12+
{
13+
value: "group-1",
14+
display: "group-1",
15+
},
16+
],
17+
userName: "user-1",
18+
roles: [],
19+
schemas: [],
20+
};
21+
const mockListClustersResponse: cluster.ListClustersResponse = {
22+
clusters: [
23+
{
24+
cluster_id: "cluster-id-2",
25+
cluster_name: "cluster-name-2",
26+
cluster_source: "UI",
27+
creator_user_name: "user-2",
28+
state: "TERMINATED",
29+
},
30+
{
31+
cluster_id: "cluster-id-1",
32+
cluster_name: "cluster-name-1",
33+
cluster_source: "UI",
34+
creator_user_name: me.userName,
35+
state: "RUNNING",
36+
},
37+
{
38+
cluster_id: "cluster-id-3",
39+
cluster_name: "cluster-name-3",
40+
cluster_source: "API",
41+
creator_user_name: me.userName,
42+
state: "RUNNING",
43+
},
44+
{
45+
cluster_id: "cluster-id-5",
46+
cluster_name: "cluster-name-5",
47+
cluster_source: "JOB",
48+
creator_user_name: me.userName,
49+
state: "RUNNING",
50+
},
51+
{
52+
cluster_id: "cluster-id-4",
53+
cluster_name: "cluster-name-4",
54+
cluster_source: "API",
55+
creator_user_name: "user-2",
56+
state: "RUNNING",
57+
single_user_name: me.userName,
58+
data_security_mode: "SINGLE_USER",
59+
},
60+
],
61+
};
62+
63+
const mockClusterPermissions: Map<string, permissions.ObjectPermissions> =
64+
new Map([
65+
[
66+
"cluster-id-1",
67+
{
68+
access_control_list: [{user_name: me.userName}],
69+
},
70+
],
71+
[
72+
"cluster-id-2",
73+
{
74+
access_control_list: [{group_name: me.groups[0].display}],
75+
},
76+
],
77+
[
78+
"cluster-id-3",
79+
{
80+
access_control_list: [],
81+
},
82+
],
83+
[
84+
"cluster-id-4",
85+
{
86+
access_control_list: [{group_name: me.groups[0].display}],
87+
},
88+
],
89+
]);
90+
describe(__filename, () => {
91+
let mockedConnectionManager: ConnectionManager;
92+
let mockedApiClient: ApiClient;
93+
94+
beforeEach(() => {
95+
mockedConnectionManager = mock(ConnectionManager);
96+
mockedApiClient = mock<ApiClient>();
97+
when<cluster.ListClustersResponse>(
98+
mockedApiClient.request(
99+
"/api/2.0/clusters/list",
100+
"GET",
101+
anything(),
102+
anything()
103+
)
104+
).thenResolve(mockListClustersResponse);
105+
when(mockedConnectionManager.apiClient).thenReturn(
106+
instance(mockedApiClient)
107+
);
108+
for (let [id, perms] of mockClusterPermissions.entries()) {
109+
when<permissions.ObjectPermissions>(
110+
mockedApiClient.request(
111+
`/api/2.0/permissions/clusters/${id}`,
112+
"GET",
113+
anything(),
114+
anything()
115+
)
116+
).thenResolve(perms);
117+
}
118+
when(mockedConnectionManager.me).thenReturn(me.userName);
119+
when(mockedConnectionManager.meDetails).thenReturn(me);
120+
});
121+
122+
it("should only load accessible clusters", async () => {
123+
const loader = spy(
124+
new ClusterLoader(instance(mockedConnectionManager))
125+
);
126+
when(loader.running).thenReturn(true);
127+
when(loader.stopped).thenReturn(false);
128+
instance(loader)._load();
129+
for (let [id, _] of instance(loader).clusters.entries()) {
130+
assert.ok(
131+
["cluster-id-2", "cluster-id-1", "cluster-id-4"].includes(id)
132+
);
133+
}
134+
});
135+
});

0 commit comments

Comments
 (0)