Skip to content

Commit f0ce155

Browse files
fix: Populate collection name with it's parent hierarchy name to main… (#188)
* fix: Populate collection name with it's parent hierarchy name to maintain name unique across resources * test: add test cases Co-authored-by: sushmith <[email protected]>
1 parent b8fd41c commit f0ce155

File tree

3 files changed

+130
-9
lines changed

3 files changed

+130
-9
lines changed

Diff for: plugins/providers/metabase/client.go

+31-4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ const (
3737
name = "name"
3838
permissionsConst = "permissions"
3939
groupConst = "group"
40+
41+
pathSeparator = "/"
4042
)
4143

4244
type ResourceGroupDetails map[string][]map[string]interface{}
@@ -195,12 +197,37 @@ func (c *client) GetCollections() ([]*Collection, error) {
195197
return nil, err
196198
}
197199

198-
var collection []*Collection
199-
if _, err := c.do(req, &collection); err != nil {
200+
var collections []*Collection
201+
result := make([]*Collection, 0)
202+
if _, err := c.do(req, &collections); err != nil {
200203
return nil, err
201204
}
202-
c.logger.Info("Fetch collections from request", "total", len(collection), req.URL)
203-
return collection, nil
205+
c.logger.Info("Fetch collections from request", "total", len(collections), req.URL)
206+
207+
collectionIdNameMap := make(map[string]string, 0)
208+
for _, collection := range collections {
209+
collectionIdNameMap[fmt.Sprintf("%v", collection.ID)] = collection.Name
210+
}
211+
212+
for _, collection := range collections {
213+
// don't add personal collection
214+
if collection.PersonalOwnerId == nil {
215+
locationPath := ""
216+
locations := strings.Split(collection.Location, pathSeparator)
217+
if len(locations) > 1 {
218+
for _, id := range locations {
219+
if name, ok := collectionIdNameMap[id]; ok && len(id) > 0 {
220+
locationPath = locationPath + name + pathSeparator
221+
}
222+
}
223+
//populate resource name as hierarchy of its parent name
224+
collection.Name = locationPath + collection.Name
225+
result = append(result, collection)
226+
}
227+
}
228+
}
229+
230+
return result, nil
204231
}
205232

206233
func (c *client) GetGroups() ([]*Group, ResourceGroupDetails, ResourceGroupDetails, error) {

Diff for: plugins/providers/metabase/client_test.go

+93
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
package metabase_test
22

33
import (
4+
"bytes"
5+
"encoding/json"
46
"errors"
7+
"fmt"
8+
"io"
9+
"io/ioutil"
10+
"net/http"
511
"testing"
612

713
"github.com/odpf/salt/log"
@@ -56,5 +62,92 @@ func TestNewClient(t *testing.T) {
5662

5763
t.Run("should return client and nil error on success", func(t *testing.T) {
5864
// TODO: test http request execution
65+
mockHttpClient := new(mocks.HTTPClient)
66+
config := &metabase.ClientConfig{
67+
Username: "test-username",
68+
Password: "test-password",
69+
Host: "http://localhost",
70+
HTTPClient: mockHttpClient,
71+
}
72+
logger := log.NewLogrus(log.LogrusWithLevel("info"))
73+
74+
sessionToken := "93df71b4-6887-46bd-b4bf-7ad3b94bd6fe"
75+
responseJSON := `{"id":"` + sessionToken + `"}`
76+
response := http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader([]byte(responseJSON)))}
77+
mockHttpClient.On("Do", mock.Anything).Return(&response, nil).Once()
78+
79+
_, actualError := metabase.NewClient(config, logger)
80+
mockHttpClient.AssertExpectations(t)
81+
assert.Nil(t, actualError)
5982
})
83+
84+
t.Run("should get collections and nil error on success", func(t *testing.T) {
85+
mockHttpClient := new(mocks.HTTPClient)
86+
config := getTestClientConfig()
87+
config.HTTPClient = mockHttpClient
88+
logger := log.NewLogrus(log.LogrusWithLevel("info"))
89+
90+
sessionToken := "93df71b4-6887-46bd-b4bf-7ad3b94bd6fe"
91+
responseJSON := `{"id":"` + sessionToken + `"}`
92+
response := http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader([]byte(responseJSON)))}
93+
94+
mockHttpClient.On("Do", mock.Anything).Return(&response, nil).Once()
95+
96+
client, err := metabase.NewClient(config, logger)
97+
assert.Nil(t, err)
98+
assert.NotNil(t, client)
99+
100+
testRequest, err := getTestRequest(sessionToken, http.MethodGet, fmt.Sprintf("%s%s", config.Host, "/api/collection"), nil)
101+
assert.Nil(t, err)
102+
103+
collectionResponseJSON := `[{"authority_level":null,"name":"Our analytics","id":"root","parent_id":null,"effective_location":null,"effective_ancestors":[],"can_write":true},{"authority_level":null,"description":null,"archived":false,"slug":"cabfares","color":"#509EE3","can_write":true,"name":"CabFares","personal_owner_id":null,"id":2,"location":"/","namespace":null},{"authority_level":null,"description":null,"archived":false,"slug":"countries","color":"#509EE3","can_write":true,"name":"Countries","personal_owner_id":null,"id":5,"location":"/4/","namespace":null},{"authority_level":null,"description":null,"archived":false,"slug":"ds_analysis","color":"#509EE3","can_write":true,"name":"DS Analysis","personal_owner_id":null,"id":3,"location":"/2/","namespace":null},{"authority_level":null,"description":null,"archived":false,"slug":"ds_analysis","color":"#509EE3","can_write":true,"name":"DS Analysis","personal_owner_id":null,"id":6,"location":"/4/5/","namespace":null},{"authority_level":null,"description":null,"archived":false,"slug":"spending","color":"#509EE3","can_write":true,"name":"Spending","personal_owner_id":null,"id":4,"location":"/","namespace":null},{"authority_level":null,"description":null,"archived":false,"slug":"summary","color":"#509EE3","can_write":true,"name":"Summary","personal_owner_id":null,"id":7,"location":"/2/3/","namespace":null},{"authority_level":null,"description":null,"archived":false,"slug":"alex_s_personal_collection","color":"#31698A","can_write":true,"name":"Alex's Personal Collection","personal_owner_id":1,"id":1,"location":"/","namespace":null}]`
104+
collectionResponse := http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader([]byte(collectionResponseJSON)))}
105+
mockHttpClient.On("Do", testRequest).Return(&collectionResponse, nil).Once()
106+
107+
expectedCollections := []metabase.Collection{
108+
{ID: float64(2), Name: "CabFares", Slug: "cabfares", Location: "/"},
109+
{ID: float64(5), Name: "Spending/Countries", Slug: "countries", Location: "/4/"},
110+
{ID: float64(3), Name: "CabFares/DS Analysis", Slug: "ds_analysis", Location: "/2/"},
111+
{ID: float64(6), Name: "Spending/Countries/DS Analysis", Slug: "ds_analysis", Location: "/4/5/"},
112+
{ID: float64(4), Name: "Spending", Slug: "spending", Location: "/", Namespace: ""},
113+
{ID: float64(7), Name: "CabFares/DS Analysis/Summary", Slug: "summary", Location: "/2/3/"},
114+
}
115+
116+
result, err1 := client.GetCollections()
117+
var collections []metabase.Collection
118+
for _, coll := range result {
119+
collections = append(collections, *coll)
120+
}
121+
assert.Nil(t, err1)
122+
assert.ElementsMatch(t, expectedCollections, collections)
123+
})
124+
}
125+
126+
func getTestClientConfig() *metabase.ClientConfig {
127+
return &metabase.ClientConfig{
128+
Username: "test-username",
129+
Password: "test-password",
130+
Host: "http://localhost",
131+
}
132+
}
133+
134+
func getTestRequest(sessionToken, method, url string, body interface{}) (*http.Request, error) {
135+
var buf io.ReadWriter
136+
if body != nil {
137+
buf = new(bytes.Buffer)
138+
err := json.NewEncoder(buf).Encode(body)
139+
if err != nil {
140+
return nil, err
141+
}
142+
}
143+
req, err := http.NewRequest(method, url, buf)
144+
if err != nil {
145+
return nil, err
146+
}
147+
if body != nil {
148+
req.Header.Set("Content-Type", "application/json")
149+
}
150+
req.Header.Set("Accept", "application/json")
151+
req.Header.Set("X-Metabase-Session", sessionToken)
152+
return req, nil
60153
}

Diff for: plugins/providers/metabase/resource.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,12 @@ func (g *Group) ToDomain() *domain.Resource {
158158
}
159159

160160
type Collection struct {
161-
ID interface{} `json:"id"`
162-
Name string `json:"name"`
163-
Slug string `json:"slug"`
164-
Location string `json:"location,omitempty"`
165-
Namespace string `json:"namespace,omitempty"`
161+
ID interface{} `json:"id"`
162+
Name string `json:"name"`
163+
Slug string `json:"slug"`
164+
Location string `json:"location,omitempty"`
165+
Namespace string `json:"namespace,omitempty"`
166+
PersonalOwnerId interface{} `json:"personal_owner_id,omitempty"`
166167
}
167168

168169
func (c *Collection) FromDomain(r *domain.Resource) error {

0 commit comments

Comments
 (0)