Skip to content

Commit 1c5226e

Browse files
committed
Allow master tenant to create cross-owner batch actions
1 parent 4deff19 commit 1c5226e

3 files changed

Lines changed: 41 additions & 13 deletions

File tree

broker/oapi/open-api.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2516,7 +2516,7 @@ paths:
25162516
$ref: '#/components/schemas/Error'
25172517
post:
25182518
summary: Create a new batch action
2519-
description: Creates a batch action for one owner. Master access must provide `symbol`; Okapi access defaults to the tenant's primary symbol when omitted.
2519+
description: Creates a batch action. Master access without `symbol` creates an unrestricted action; Okapi access without `symbol` defaults to the tenant's primary symbol.
25202520
tags:
25212521
- scheduler-api
25222522
parameters:

broker/scheduler/api/api_handler.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ func (h SchedulerApiHandler) PostBatchActions(w http.ResponseWriter, r *http.Req
123123
return
124124
}
125125

126-
owner, ok := h.resolveConcreteOwner(ctx, w, r, params.Symbol)
126+
owner, ok := h.resolveBatchActionOwner(ctx, w, r, params.Symbol)
127127
if !ok {
128128
return
129129
}
@@ -325,8 +325,9 @@ func (h SchedulerApiHandler) resolveOwnerScope(ctx common.ExtendedContext, w htt
325325
return owners, true
326326
}
327327

328-
// resolveConcreteOwner resolves the single owner required when creating a task.
329-
func (h SchedulerApiHandler) resolveConcreteOwner(ctx common.ExtendedContext, w http.ResponseWriter, r *http.Request, symbol *string) (string, bool) {
328+
// resolveBatchActionOwner resolves the owner for a new batch action. An empty
329+
// owner represents unrestricted master access.
330+
func (h SchedulerApiHandler) resolveBatchActionOwner(ctx common.ExtendedContext, w http.ResponseWriter, r *http.Request, symbol *string) (string, bool) {
330331
t, err := h.tenantResolver.Resolve(ctx, r, symbol)
331332
if err != nil {
332333
brokerapi.AddBadRequestError(ctx, w, err)
@@ -337,10 +338,6 @@ func (h SchedulerApiHandler) resolveConcreteOwner(ctx common.ExtendedContext, w
337338
brokerapi.AddBadRequestError(ctx, w, err)
338339
return "", false
339340
}
340-
if owner == "" {
341-
brokerapi.AddBadRequestError(ctx, w, errors.New("symbol must be specified when creating a batch action with master access"))
342-
return "", false
343-
}
344341
return owner, true
345342
}
346343

broker/scheduler/api/api_handler_test.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -409,17 +409,48 @@ func TestPostBatchActions_ActionParamsPersisted(t *testing.T) {
409409
repo.AssertExpectations(t)
410410
}
411411

412-
func TestPostBatchActions_MasterWithoutSymbolReturnsBadRequest(t *testing.T) {
412+
func TestPostBatchActions_MasterWithoutSymbolCreatesUnrestrictedAction(t *testing.T) {
413413
repo := new(MockSchedRepo)
414+
repo.On("SaveScheduledTask", mock.MatchedBy(func(p sched_db.SaveScheduledTaskParams) bool {
415+
return p.Owner == "" &&
416+
p.ActionData.BatchActionData != nil &&
417+
p.ActionData.BatchActionData.Owner == ""
418+
})).Return(saveScheduledTaskReturn, nil)
419+
414420
h := newHandler(repo)
415-
req := newReq(http.MethodPost, `{"actionName":"email-pullslips","batchQuery":"title=test","schedule":"`+validRrule+`"}`)
421+
req := newReq(http.MethodPost, `{"actionName":"request-aging","batchQuery":"title=test","schedule":"`+validRrule+`","actionParams":{"interval":"24h"}}`)
416422
rr := httptest.NewRecorder()
417423

418424
h.PostBatchActions(rr, req, schedoapi.PostBatchActionsParams{})
419425

420-
assert.Equal(t, http.StatusBadRequest, rr.Code)
421-
assert.Contains(t, rr.Body.String(), "symbol must be specified")
422-
repo.AssertNotCalled(t, "SaveScheduledTask", mock.Anything)
426+
assert.Equal(t, http.StatusCreated, rr.Code)
427+
var resp schedoapi.BatchAction
428+
assert.NoError(t, json.Unmarshal(rr.Body.Bytes(), &resp))
429+
assert.Equal(t, schedoapi.RequestAging, resp.ActionName)
430+
repo.AssertExpectations(t)
431+
}
432+
433+
func TestPostBatchActions_OkapiWithoutSymbolUsesPrimaryMappedOwner(t *testing.T) {
434+
const mappedOwner = "ISIL:DK-DIKU"
435+
repo := new(MockSchedRepo)
436+
repo.On("SaveScheduledTask", mock.MatchedBy(func(p sched_db.SaveScheduledTaskParams) bool {
437+
return p.Owner == mappedOwner &&
438+
p.ActionData.BatchActionData != nil &&
439+
p.ActionData.BatchActionData.Owner == mappedOwner
440+
})).Return(saveScheduledTaskReturn, nil)
441+
resolver := tenant.NewResolver().
442+
WithTenantToSymbol("ISIL:DK-{tenant}").
443+
WithIllRepo(new(testmocks.MockIllRepositorySuccess))
444+
h := NewSchedulerApiHandler(10, repo, nil, resolver)
445+
req := httptest.NewRequest(http.MethodPost, "/broker/batch_actions",
446+
strings.NewReader(`{"actionName":"request-aging","batchQuery":"title=test","schedule":"`+validRrule+`","actionParams":{"interval":"24h"}}`))
447+
req.Header.Set(tenant.OkapiTenantHeader, "diku")
448+
rr := httptest.NewRecorder()
449+
450+
h.PostBatchActions(rr, req, schedoapi.PostBatchActionsParams{})
451+
452+
assert.Equal(t, http.StatusCreated, rr.Code)
453+
repo.AssertExpectations(t)
423454
}
424455

425456
func TestPostBatchActions_MissingBody(t *testing.T) {

0 commit comments

Comments
 (0)