Skip to content

Commit

Permalink
search
Browse files Browse the repository at this point in the history
  • Loading branch information
reinkrul committed Dec 9, 2023
1 parent 0f56507 commit bc8b352
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 55 deletions.
40 changes: 17 additions & 23 deletions discovery/api/v1/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions discovery/api/v1/wapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var _ core.ErrorStatusCodeResolver = (*Wrapper)(nil)

type Wrapper struct {
Server discovery.Server
Client discovery.Client
}

func (w *Wrapper) ResolveStatusCode(err error) int {
Expand Down Expand Up @@ -84,6 +85,17 @@ func (w *Wrapper) RegisterPresentation(_ context.Context, request RegisterPresen
}

func (w *Wrapper) SearchPresentations(_ context.Context, request SearchPresentationsRequestObject) (SearchPresentationsResponseObject, error) {
// TODO: Do we need this from the start on, or are we hooking up VCR.SearchVCs to Discovery.Search()?
panic("implement me")
searchResults, err := w.Client.Search(request.ServiceID, request.Params.Query)
if err != nil {
return nil, err
}
var result []SearchResult
for _, searchResult := range searchResults {
result = append(result, SearchResult{
Vp: searchResult.VP,
Id: searchResult.VP.ID.String(),
Fields: searchResult.Fields,
})
}
return SearchPresentations200JSONResponse(result), nil
}
81 changes: 65 additions & 16 deletions discovery/api/v1/wapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
package v1

import (
ssi "github.com/nuts-foundation/go-did"
"github.com/nuts-foundation/go-did/vc"
"github.com/nuts-foundation/nuts-node/discovery"
"github.com/nuts-foundation/nuts-node/vcr/credential"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
Expand Down Expand Up @@ -64,22 +66,6 @@ func TestWrapper_GetPresentations(t *testing.T) {
})
}

type mockContext struct {
ctrl *gomock.Controller
server *discovery.MockServer
wrapper Wrapper
}

func newMockContext(t *testing.T) mockContext {
ctrl := gomock.NewController(t)
server := discovery.NewMockServer(ctrl)
return mockContext{
ctrl: ctrl,
server: server,
wrapper: Wrapper{server},
}
}

func TestWrapper_RegisterPresentation(t *testing.T) {
t.Run("ok", func(t *testing.T) {
test := newMockContext(t)
Expand Down Expand Up @@ -107,3 +93,66 @@ func TestWrapper_RegisterPresentation(t *testing.T) {
assert.ErrorIs(t, err, discovery.ErrInvalidPresentation)
})
}

func TestWrapper_SearchPresentations(t *testing.T) {
query := map[string]string{
"foo": "bar",
}
id, _ := ssi.ParseURI("did:nuts:foo#1")
vp := vc.VerifiablePresentation{
ID: id,
VerifiableCredential: []vc.VerifiableCredential{credential.ValidNutsOrganizationCredential(t)},
}
t.Run("ok", func(t *testing.T) {
test := newMockContext(t)
results := []discovery.SearchResult{
{
VP: vp,
Fields: nil,
},
}
test.client.EXPECT().Search(serviceID, query).Return(results, nil)

response, err := test.wrapper.SearchPresentations(nil, SearchPresentationsRequestObject{
ServiceID: serviceID,
Params: SearchPresentationsParams{Query: query},
})

assert.NoError(t, err)
assert.IsType(t, SearchPresentations200JSONResponse{}, response)
actual := response.(SearchPresentations200JSONResponse)
require.Len(t, actual, 1)
assert.Equal(t, vp, actual[0].Vp)
assert.Equal(t, vp.ID.String(), actual[0].Id)
})
t.Run("error", func(t *testing.T) {
test := newMockContext(t)
test.client.EXPECT().Search(serviceID, query).Return(nil, discovery.ErrServiceNotFound)

_, err := test.wrapper.SearchPresentations(nil, SearchPresentationsRequestObject{
ServiceID: serviceID,
Params: SearchPresentationsParams{Query: query},
})

assert.ErrorIs(t, err, discovery.ErrServiceNotFound)
})
}

type mockContext struct {
ctrl *gomock.Controller
server *discovery.MockServer
client *discovery.MockClient
wrapper Wrapper
}

func newMockContext(t *testing.T) mockContext {
ctrl := gomock.NewController(t)
server := discovery.NewMockServer(ctrl)
client := discovery.NewMockClient(ctrl)
return mockContext{
ctrl: ctrl,
server: server,
client: client,
wrapper: Wrapper{Server: server, Client: client},
}
}
7 changes: 6 additions & 1 deletion discovery/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,10 @@ type Server interface {

// Client defines the API for Discovery Clients.
type Client interface {
Search(serviceID string, query map[string]string) ([]vc.VerifiablePresentation, error)
Search(serviceID string, query map[string]string) ([]SearchResult, error)
}

type SearchResult struct {
VP vc.VerifiablePresentation
Fields map[string]string
}
4 changes: 2 additions & 2 deletions discovery/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions discovery/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ var _ core.Injectable = &Module{}
var _ core.Runnable = &Module{}
var _ core.Configurable = &Module{}
var _ Server = &Module{}
var _ Client = &Module{}

var retractionPresentationType = ssi.MustParseURI("RetractedVerifiablePresentation")

Expand Down Expand Up @@ -253,3 +254,22 @@ func loadDefinitions(directory string) (map[string]ServiceDefinition, error) {
}
return result, nil
}

func (m *Module) Search(serviceID string, query map[string]string) ([]SearchResult, error) {
if _, exists := m.serverDefinitions[serviceID]; !exists {
return nil, ErrServerModeDisabled
}
matchingVPs, err := m.store.search(serviceID, query)
if err != nil {
return nil, err
}
var result []SearchResult
for _, matchingVP := range matchingVPs {
result = append(result, SearchResult{
VP: matchingVP,
// TODO: TokenIntrospection is also missing map[InputDescriptorId]CredentialValue ?
//Fields: matchingVP.Fields,
})
}
return result, nil
}
24 changes: 24 additions & 0 deletions discovery/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,27 @@ func TestModule_Configure(t *testing.T) {
assert.ErrorContains(t, err, "unable to read definitions directory 'test/non_existent'")
})
}

func TestModule_Search(t *testing.T) {
storageEngine := storage.NewTestStorageEngine(t)
require.NoError(t, storageEngine.Start())
t.Run("ok", func(t *testing.T) {
m, _ := setupModule(t, storageEngine)
require.NoError(t, m.store.add(testServiceID, vpAlice, nil))
results, err := m.Search(testServiceID, map[string]string{
"credentialSubject.id": aliceDID.String(),
})
assert.NoError(t, err)
assert.Equal(t, []SearchResult{
{
VP: vpAlice,
Fields: nil,
},
}, results)
})
t.Run("not a client for this service ID", func(t *testing.T) {
m, _ := setupModule(t, storageEngine)
_, err := m.Search("other", nil)
assert.ErrorIs(t, err, ErrServerModeDisabled)
})
}
30 changes: 19 additions & 11 deletions docs/_static/discovery/v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -132,23 +132,31 @@ paths:
schema:
type: array
items:
type: object
required:
- id
- credential
properties:
id:
type: string
description: The ID of the Verifiable Presentation.
credential:
type: object
description: The Verifiable Credential that matched the query.
$ref: "#/components/schemas/SearchResult"
default:
$ref: "../common/error_response.yaml"
components:
schemas:
VerifiablePresentation:
$ref: "../common/ssi_types.yaml#/components/schemas/VerifiablePresentation"
SearchResult:
type: object
required:
- id
- vp
- fields
properties:
id:
type: string
description: The ID of the Verifiable Presentation.
vp:
$ref: "#/components/schemas/VerifiablePresentation"
fields:
type: object
description: Input descriptor IDs and their mapped values that from the Verifiable Credential.
additionalProperties:
type: string
description: The value of the field that matched the query.
securitySchemes:
jwtBearerAuth:
type: http
Expand Down

0 comments on commit bc8b352

Please sign in to comment.