diff --git a/sdk/messaging/azeventgrid/assets.json b/sdk/messaging/azeventgrid/assets.json index 0189b4352a79..de7380b8dcf6 100644 --- a/sdk/messaging/azeventgrid/assets.json +++ b/sdk/messaging/azeventgrid/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/messaging/azeventgrid", - "Tag": "go/messaging/azeventgrid_601fd733f2" + "Tag": "go/messaging/azeventgrid_b8c3771d17" } diff --git a/sdk/messaging/azeventgrid/autorest.md b/sdk/messaging/azeventgrid/autorest.md index 4ee2fddc2a89..a8927d4dff73 100644 --- a/sdk/messaging/azeventgrid/autorest.md +++ b/sdk/messaging/azeventgrid/autorest.md @@ -25,15 +25,6 @@ directive: - from: client.go where: $ transform: return $.replace(/PublishCloudEvents\(/g, "internalPublishCloudEvents("); - # make sure the casing of the properties is what compliant. - # - from: swagger-document - # where: $.definitions.CloudEvent.properties.data - # transform: > - # $["type"] = "array" - # - from: swagger-document - # where: $.definitions.CloudEvent.properties.data - # transform: > - # $["items"] = {"type": "byte"} - from: swagger-document where: $.definitions.CloudEvent.properties.specversion transform: $["x-ms-client-name"] = "SpecVersion" @@ -43,6 +34,19 @@ directive: - from: swagger-document where: $.definitions.CloudEvent.properties.dataschema transform: $["x-ms-client-name"] = "DataSchema" + # mark models as external so they're just omitted + - from: swagger-document + where: $.definitions.CloudEvent + transform: $["x-ms-external"] = true + - from: swagger-document + where: $.definitions.["Azure.Core.Foundations.Error"] + transform: $["x-ms-external"] = true + - from: swagger-document + where: $.definitions.["Azure.Core.Foundations.ErrorResponse"] + transform: $["x-ms-external"] = true + - from: swagger-document + where: $.definitions.["Azure.Core.Foundations.InnerError"] + transform: $["x-ms-external"] = true # make the endpoint a parameter of the client constructor - from: swagger-document where: $["x-ms-parameterized-host"] @@ -54,11 +58,11 @@ directive: - response_types.go where: $ transform: return $.replace(/Client(\w+)((?:Options|Response))/g, "$1$2"); + # replace references to the "generated" CloudEvent to the actual version in azcore/messaging - from: - client.go - models.go - - models_serde.go - response_types.go where: $ - transform: return $.replace(/AzureCoreFoundations/g, ""); + transform: return $.replace(/\*CloudEvent/g, "messaging.CloudEvent"); ``` diff --git a/sdk/messaging/azeventgrid/build.go b/sdk/messaging/azeventgrid/build.go index 98ce5cd2b813..dc492eae47a5 100644 --- a/sdk/messaging/azeventgrid/build.go +++ b/sdk/messaging/azeventgrid/build.go @@ -4,6 +4,6 @@ // +build go1.18 //go:generate autorest ./autorest.md -//go:generate gofmt -w . +//go:generate goimports -w . package azeventgrid diff --git a/sdk/messaging/azeventgrid/ci.yml b/sdk/messaging/azeventgrid/ci.yml index 093eb520154e..b3cfa6b86fd7 100644 --- a/sdk/messaging/azeventgrid/ci.yml +++ b/sdk/messaging/azeventgrid/ci.yml @@ -2,28 +2,29 @@ trigger: branches: include: - - main - - feature/* - - hotfix/* - - release/* + - main + - feature/* + - hotfix/* + - release/* paths: include: - - sdk/messaging/azeventgrid - - eng/ + - sdk/messaging/azeventgrid + - eng/ pr: branches: include: - - main - - feature/* - - hotfix/* - - release/* + - main + - feature/* + - hotfix/* + - release/* paths: include: - - sdk/messaging/azeventgrid - + - sdk/messaging/azeventgrid stages: -- template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml - parameters: - ServiceDirectory: 'messaging/azeventgrid' + - template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: "messaging/azeventgrid" + RunLiveTests: true + Location: westus2 diff --git a/sdk/messaging/azeventgrid/client.go b/sdk/messaging/azeventgrid/client.go index da5c52aa33bd..a9f2eb682841 100644 --- a/sdk/messaging/azeventgrid/client.go +++ b/sdk/messaging/azeventgrid/client.go @@ -1,5 +1,3 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. //go:build go1.18 // +build go1.18 @@ -14,13 +12,15 @@ package azeventgrid import ( "context" "errors" - "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "net/http" "net/url" "strconv" "strings" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/messaging" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" ) // Client contains the methods for the Client group. @@ -101,7 +101,7 @@ func (client *Client) acknowledgeCloudEventsHandleResponse(resp *http.Response) // - topicName - Topic Name. // - events - Array of Cloud Events being published. // - options - PublishCloudEventsOptions contains the optional parameters for the Client.PublishCloudEvents method. -func (client *Client) internalPublishCloudEvents(ctx context.Context, topicName string, events []*CloudEvent, options *PublishCloudEventsOptions) (PublishCloudEventsResponse, error) { +func (client *Client) internalPublishCloudEvents(ctx context.Context, topicName string, events []messaging.CloudEvent, options *PublishCloudEventsOptions) (PublishCloudEventsResponse, error) { req, err := client.publishCloudEventsCreateRequest(ctx, topicName, events, options) if err != nil { return PublishCloudEventsResponse{}, err @@ -117,7 +117,7 @@ func (client *Client) internalPublishCloudEvents(ctx context.Context, topicName } // publishCloudEventsCreateRequest creates the PublishCloudEvents request. -func (client *Client) publishCloudEventsCreateRequest(ctx context.Context, topicName string, events []*CloudEvent, options *PublishCloudEventsOptions) (*policy.Request, error) { +func (client *Client) publishCloudEventsCreateRequest(ctx context.Context, topicName string, events []messaging.CloudEvent, options *PublishCloudEventsOptions) (*policy.Request, error) { urlPath := "/topics/{topicName}:publish" if topicName == "" { return nil, errors.New("parameter topicName cannot be empty") diff --git a/sdk/messaging/azeventgrid/client_custom.go b/sdk/messaging/azeventgrid/client_custom.go index 6dcee91c22a3..cba474c18d50 100644 --- a/sdk/messaging/azeventgrid/client_custom.go +++ b/sdk/messaging/azeventgrid/client_custom.go @@ -13,10 +13,9 @@ import ( "net/http" "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/messaging" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" - "github.com/Azure/azure-sdk-for-go/sdk/internal/uuid" ) // ClientOptions contains optional settings for [Client] @@ -59,27 +58,11 @@ func NewClientWithSharedKeyCredential(endpoint string, key string, options *Clie // - topicName - Topic Name. // - events - Array of Cloud Events being published. // - options - ClientPublishCloudEventsOptions contains the optional parameters for the Client.PublishCloudEvents method. -func (client *Client) PublishCloudEvents(ctx context.Context, topicName string, events []*CloudEvent, options *PublishCloudEventsOptions) (PublishCloudEventsResponse, error) { +func (client *Client) PublishCloudEvents(ctx context.Context, topicName string, events []messaging.CloudEvent, options *PublishCloudEventsOptions) (PublishCloudEventsResponse, error) { ctx = runtime.WithHTTPHeader(ctx, http.Header{ "Content-type": []string{"application/cloudevents-batch+json; charset=utf-8"}, }) - for _, evt := range events { - if evt.ID == nil { - id, err := uuid.New() - - if err != nil { - return PublishCloudEventsResponse{}, err - } - - evt.ID = to.Ptr(id.String()) - } - - if evt.SpecVersion == nil || *evt.SpecVersion == "" { - evt.SpecVersion = &defaultSpecVersion - } - } - return client.internalPublishCloudEvents(ctx, topicName, events, options) } @@ -92,5 +75,3 @@ func (p *skpolicy) Do(req *policy.Request) (*http.Response, error) { req.Raw().Header.Add("Authorization", "SharedAccessKey "+p.Key) return req.Next() } - -var defaultSpecVersion = "1.0" diff --git a/sdk/messaging/azeventgrid/client_test.go b/sdk/messaging/azeventgrid/client_test.go index bf78fe73b604..04ec52347fda 100644 --- a/sdk/messaging/azeventgrid/client_test.go +++ b/sdk/messaging/azeventgrid/client_test.go @@ -8,8 +8,12 @@ package azeventgrid_test import ( "context" + "encoding/json" + "net/http" "testing" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/messaging" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventgrid" "github.com/stretchr/testify/require" @@ -18,13 +22,10 @@ import ( func TestFailedAck(t *testing.T) { c := newClientWrapper(t, nil) - pubResp, err := c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []*azeventgrid.CloudEvent{ - { - Data: []byte("ack this one"), - Source: to.Ptr("hello-source"), - Type: to.Ptr("world"), - }, - }, nil) + ce, err := messaging.NewCloudEvent("hello-source", "world", []byte("ack this one"), nil) + require.NoError(t, err) + + pubResp, err := c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []messaging.CloudEvent{ce}, nil) require.NoError(t, err) // just documenting this, I don't think the return value is useful. @@ -96,18 +97,13 @@ func TestFailedAck(t *testing.T) { func TestPartialAckFailure(t *testing.T) { c := newClientWrapper(t, nil) - _, err := c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []*azeventgrid.CloudEvent{ - { - Data: []byte("event one"), - Source: to.Ptr("hello-source"), - Type: to.Ptr("world"), - }, - { - Data: []byte("event two"), - Source: to.Ptr("hello-source"), - Type: to.Ptr("world"), - }, - }, nil) + ce, err := messaging.NewCloudEvent("hello-source", "world", []byte("event one"), nil) + require.NoError(t, err) + + ce2, err := messaging.NewCloudEvent("hello-source", "world", []byte("event two"), nil) + require.NoError(t, err) + + _, err = c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []messaging.CloudEvent{ce, ce2}, nil) require.NoError(t, err) events, err := c.ReceiveCloudEvents(context.Background(), c.TestVars.Topic, c.TestVars.Subscription, &azeventgrid.ReceiveCloudEventsOptions{ @@ -143,22 +139,20 @@ func TestPartialAckFailure(t *testing.T) { func TestReject(t *testing.T) { c := newClientWrapper(t, nil) - _, err := c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []*azeventgrid.CloudEvent{ - { - Data: "event one", - Source: to.Ptr("TestAbandon"), - Type: to.Ptr("world"), - }, - }, nil) + ce, err := messaging.NewCloudEvent("TestAbandon", "world", []byte("event one"), nil) + require.NoError(t, err) + + _, err = c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []messaging.CloudEvent{ce}, nil) require.NoError(t, err) events, err := c.ReceiveCloudEvents(context.Background(), c.TestVars.Topic, c.TestVars.Subscription, nil) require.NoError(t, err) - requireEqualCloudEvent(t, &azeventgrid.CloudEvent{ - Data: "event one", - Source: to.Ptr("TestAbandon"), - Type: to.Ptr("world"), + requireEqualCloudEvent(t, messaging.CloudEvent{ + SpecVersion: "1.0", + Data: []byte("event one"), + Source: "TestAbandon", + Type: "world", }, events.Value[0].Event) require.Equal(t, int32(1), *events.Value[0].BrokerProperties.DeliveryCount, "DeliveryCount starts at 1") @@ -179,23 +173,17 @@ func TestReject(t *testing.T) { func TestRelease(t *testing.T) { c := newClientWrapper(t, nil) - _, err := c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []*azeventgrid.CloudEvent{ - { - Data: "event one", - Source: to.Ptr("TestAbandon"), - Type: to.Ptr("world"), - }, - }, nil) + + ce, err := messaging.NewCloudEvent("TestAbandon", "world", []byte("event one"), nil) + require.NoError(t, err) + + _, err = c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []messaging.CloudEvent{ce}, nil) require.NoError(t, err) events, err := c.ReceiveCloudEvents(context.Background(), c.TestVars.Topic, c.TestVars.Subscription, nil) require.NoError(t, err) - requireEqualCloudEvent(t, &azeventgrid.CloudEvent{ - Data: "event one", - Source: to.Ptr("TestAbandon"), - Type: to.Ptr("world"), - }, events.Value[0].Event) + requireEqualCloudEvent(t, ce, events.Value[0].Event) require.Equal(t, int32(1), *events.Value[0].BrokerProperties.DeliveryCount, "DeliveryCount starts at 1") @@ -218,23 +206,65 @@ func TestRelease(t *testing.T) { func TestPublishingAndReceivingCloudEvents(t *testing.T) { c := newClientWrapper(t, nil) - _, err := c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []*azeventgrid.CloudEvent{ - { - Data: "hello world", - Source: to.Ptr("hello-source"), - Type: to.Ptr("world"), + + ce1, err := messaging.NewCloudEvent("hello-source", "eventType", "hello world 1", nil) + require.NoError(t, err) + + ce2, err := messaging.NewCloudEvent("hello-source", "eventType", "hello world 2", &messaging.CloudEventOptions{ + DataContentType: to.Ptr("data content type"), + DataSchema: to.Ptr("https://dataschema"), + Extensions: map[string]any{ + "extension1": "extension1value", }, - }, nil) + Subject: to.Ptr("subject"), + }) + require.NoError(t, err) + + type simpleType struct { + Name string + } + + ce3, err := messaging.NewCloudEvent("hello-source", "eventType", simpleType{Name: "simple type name"}, nil) require.NoError(t, err) - resp, err := c.ReceiveCloudEvents(context.Background(), c.TestVars.Topic, c.TestVars.Subscription, nil) + _, err = c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []messaging.CloudEvent{ce1, ce2, ce3}, nil) + require.NoError(t, err) + + resp, err := c.ReceiveCloudEvents(context.Background(), c.TestVars.Topic, c.TestVars.Subscription, &azeventgrid.ReceiveCloudEventsOptions{ + MaxEvents: to.Ptr[int32](3), + }) require.NoError(t, err) require.NotEmpty(t, resp.Value) - // this doesn't work - it comes back as a base64 encoded string. - require.Equal(t, "hello world", resp.Value[0].Event.Data) - require.Equal(t, "hello-source", *resp.Value[0].Event.Source) - require.Equal(t, "world", *resp.Value[0].Event.Type) + requireEqualCloudEvent(t, messaging.CloudEvent{ + SpecVersion: "1.0", + Source: "hello-source", + Type: "eventType", + Data: json.RawMessage("\"hello world 1\""), + }, resp.Value[0].Event) + + requireEqualCloudEvent(t, messaging.CloudEvent{ + SpecVersion: "1.0", + Source: "hello-source", + Type: "eventType", + DataSchema: to.Ptr("https://dataschema"), + Data: json.RawMessage("\"hello world 2\""), + DataContentType: to.Ptr("data content type"), + Subject: to.Ptr("subject"), + Extensions: map[string]any{ + "extension1": "extension1value", + }, + }, resp.Value[1].Event) + + bytes, err := json.Marshal(simpleType{Name: "simple type name"}) + require.NoError(t, err) + + requireEqualCloudEvent(t, messaging.CloudEvent{ + SpecVersion: "1.0", + Source: "hello-source", + Type: "eventType", + Data: json.RawMessage(bytes), + }, resp.Value[2].Event) ackArgs := azeventgrid.AcknowledgeOptions{} @@ -250,4 +280,15 @@ func TestPublishingAndReceivingCloudEvents(t *testing.T) { require.NotEmpty(t, ackResp.SucceededLockTokens) } -// https://github.com/cloudevents/spec/blob/v1.0/json-format.md#31-handling-of-data +func TestSimpleErrors(t *testing.T) { + c := newClientWrapper(t, nil) + + _, err := c.PublishCloudEvents(context.Background(), c.TestVars.Topic, []messaging.CloudEvent{ + {}, + }, nil) + var respErr *azcore.ResponseError + + require.ErrorAs(t, err, &respErr) + require.Equal(t, http.StatusBadRequest, respErr.StatusCode) + require.Contains(t, respErr.Error(), "'data' attribute is required") +} diff --git a/sdk/messaging/azeventgrid/go.mod b/sdk/messaging/azeventgrid/go.mod index 21970fdfe483..9229d59d846a 100644 --- a/sdk/messaging/azeventgrid/go.mod +++ b/sdk/messaging/azeventgrid/go.mod @@ -3,12 +3,14 @@ module github.com/Azure/azure-sdk-for-go/sdk/messaging/azeventgrid go 1.18 require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0-beta.3 github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 github.com/joho/godotenv v1.5.1 github.com/stretchr/testify v1.7.0 ) +replace github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0-beta.3 => ../../azcore + require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dnaeon/go-vcr v1.1.0 // indirect diff --git a/sdk/messaging/azeventgrid/go.sum b/sdk/messaging/azeventgrid/go.sum index b83312d72c1f..67a56ca0f73e 100644 --- a/sdk/messaging/azeventgrid/go.sum +++ b/sdk/messaging/azeventgrid/go.sum @@ -1,5 +1,3 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1 h1:SEy2xmstIphdPwNBUi7uhvjyjhVKISfwjfOJmuy7kg4= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/sdk/messaging/azeventgrid/models.go b/sdk/messaging/azeventgrid/models.go index a31c9bf57e04..2784b50973a8 100644 --- a/sdk/messaging/azeventgrid/models.go +++ b/sdk/messaging/azeventgrid/models.go @@ -1,5 +1,3 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. //go:build go1.18 // +build go1.18 @@ -11,7 +9,7 @@ package azeventgrid -import "time" +import "github.com/Azure/azure-sdk-for-go/sdk/azcore/messaging" // AcknowledgeOptions - Array of lock token strings for the corresponding received Cloud Events to be acknowledged. type AcknowledgeOptions struct { @@ -29,41 +27,6 @@ type AcknowledgeResult struct { SucceededLockTokens []*string } -// Error - The error object. -type Error struct { - // REQUIRED; One of a server-defined set of error codes. - Code *string - - // REQUIRED; An array of details about specific errors that led to this reported error. - Details []*Error - - // REQUIRED; A human-readable representation of the error. - Message *string - - // An object containing more specific information than the current object about the error. - Innererror *InnerError - - // The target of the error. - Target *string -} - -// ErrorResponse - A response containing error details. -type ErrorResponse struct { - // REQUIRED; The error object. - Error *Error -} - -// InnerError - An object containing more specific information about the error. As per Microsoft One API -// guidelines - -// https://github.com/Microsoft/api-guidelines/blob/vNext/Guidelines.md#7102-error-condition-responses. -type InnerError struct { - // REQUIRED; One of a server-defined set of error codes. - Code *string - - // Inner error. - Innererror *InnerError -} - // BrokerProperties - Properties of the Event Broker operation. type BrokerProperties struct { // REQUIRED; The attempt count for delivering the event. @@ -105,41 +68,6 @@ type ReleaseCloudEventsOptions struct { // placeholder for future optional parameters } -// CloudEvent - Properties of an event published to an Azure Messaging EventGrid Namespace topic using the CloudEvent 1.0 -// Schema. -type CloudEvent struct { - // REQUIRED; An identifier for the event. The combination of id and source must be unique for each distinct event. - ID *string - - // REQUIRED; Identifies the context in which an event happened. The combination of id and source must be unique for each distinct - // event. - Source *string - - // REQUIRED; The version of the CloudEvents specification which the event uses. - SpecVersion *string - - // REQUIRED; Type of event related to the originating occurrence. - Type *string - - // Event data specific to the event type. - Data any - - // Event data specific to the event type, encoded as a base64 string. - DataBase64 []byte - - // Content type of data value. - DataContentType *string - - // Identifies the schema that data adheres to. - DataSchema *string - - // This describes the subject of the event in the context of the event producer (identified by source). - Subject *string - - // The time (in UTC) the event was generated, in RFC3339 format. - Time *time.Time -} - // FailedLockToken - Failed LockToken information. type FailedLockToken struct { // REQUIRED; Error code related to the token. Example of such error codes are BadToken: which indicates the Token is not formatted @@ -160,7 +88,7 @@ type ReceiveDetails struct { BrokerProperties *BrokerProperties // REQUIRED; Cloud Event details. - Event *CloudEvent + Event messaging.CloudEvent } // ReceiveResult - Details of the Receive operation response. diff --git a/sdk/messaging/azeventgrid/models_serde.go b/sdk/messaging/azeventgrid/models_serde.go index 7faf3a798eef..736f0a5b1835 100644 --- a/sdk/messaging/azeventgrid/models_serde.go +++ b/sdk/messaging/azeventgrid/models_serde.go @@ -1,5 +1,3 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. //go:build go1.18 // +build go1.18 @@ -14,9 +12,9 @@ package azeventgrid import ( "encoding/json" "fmt" - "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "reflect" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" ) // MarshalJSON implements the json.Marshaller interface for type AcknowledgeOptions. @@ -77,107 +75,6 @@ func (a *AcknowledgeResult) UnmarshalJSON(data []byte) error { return nil } -// MarshalJSON implements the json.Marshaller interface for type Error. -func (a Error) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]any) - populate(objectMap, "code", a.Code) - populate(objectMap, "details", a.Details) - populate(objectMap, "innererror", a.Innererror) - populate(objectMap, "message", a.Message) - populate(objectMap, "target", a.Target) - return json.Marshal(objectMap) -} - -// UnmarshalJSON implements the json.Unmarshaller interface for type Error. -func (a *Error) UnmarshalJSON(data []byte) error { - var rawMsg map[string]json.RawMessage - if err := json.Unmarshal(data, &rawMsg); err != nil { - return fmt.Errorf("unmarshalling type %T: %v", a, err) - } - for key, val := range rawMsg { - var err error - switch key { - case "code": - err = unpopulate(val, "Code", &a.Code) - delete(rawMsg, key) - case "details": - err = unpopulate(val, "Details", &a.Details) - delete(rawMsg, key) - case "innererror": - err = unpopulate(val, "Innererror", &a.Innererror) - delete(rawMsg, key) - case "message": - err = unpopulate(val, "Message", &a.Message) - delete(rawMsg, key) - case "target": - err = unpopulate(val, "Target", &a.Target) - delete(rawMsg, key) - } - if err != nil { - return fmt.Errorf("unmarshalling type %T: %v", a, err) - } - } - return nil -} - -// MarshalJSON implements the json.Marshaller interface for type ErrorResponse. -func (a ErrorResponse) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]any) - populate(objectMap, "error", a.Error) - return json.Marshal(objectMap) -} - -// UnmarshalJSON implements the json.Unmarshaller interface for type ErrorResponse. -func (a *ErrorResponse) UnmarshalJSON(data []byte) error { - var rawMsg map[string]json.RawMessage - if err := json.Unmarshal(data, &rawMsg); err != nil { - return fmt.Errorf("unmarshalling type %T: %v", a, err) - } - for key, val := range rawMsg { - var err error - switch key { - case "error": - err = unpopulate(val, "Error", &a.Error) - delete(rawMsg, key) - } - if err != nil { - return fmt.Errorf("unmarshalling type %T: %v", a, err) - } - } - return nil -} - -// MarshalJSON implements the json.Marshaller interface for type InnerError. -func (a InnerError) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]any) - populate(objectMap, "code", a.Code) - populate(objectMap, "innererror", a.Innererror) - return json.Marshal(objectMap) -} - -// UnmarshalJSON implements the json.Unmarshaller interface for type InnerError. -func (a *InnerError) UnmarshalJSON(data []byte) error { - var rawMsg map[string]json.RawMessage - if err := json.Unmarshal(data, &rawMsg); err != nil { - return fmt.Errorf("unmarshalling type %T: %v", a, err) - } - for key, val := range rawMsg { - var err error - switch key { - case "code": - err = unpopulate(val, "Code", &a.Code) - delete(rawMsg, key) - case "innererror": - err = unpopulate(val, "Innererror", &a.Innererror) - delete(rawMsg, key) - } - if err != nil { - return fmt.Errorf("unmarshalling type %T: %v", a, err) - } - } - return nil -} - // MarshalJSON implements the json.Marshaller interface for type BrokerProperties. func (b BrokerProperties) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -209,69 +106,6 @@ func (b *BrokerProperties) UnmarshalJSON(data []byte) error { return nil } -// MarshalJSON implements the json.Marshaller interface for type CloudEvent. -func (c CloudEvent) MarshalJSON() ([]byte, error) { - objectMap := make(map[string]any) - populateAny(objectMap, "data", c.Data) - populateByteArray(objectMap, "data_base64", c.DataBase64, runtime.Base64StdFormat) - populate(objectMap, "datacontenttype", c.DataContentType) - populate(objectMap, "dataschema", c.DataSchema) - populate(objectMap, "id", c.ID) - populate(objectMap, "source", c.Source) - populate(objectMap, "specversion", c.SpecVersion) - populate(objectMap, "subject", c.Subject) - populateTimeRFC3339(objectMap, "time", c.Time) - populate(objectMap, "type", c.Type) - return json.Marshal(objectMap) -} - -// UnmarshalJSON implements the json.Unmarshaller interface for type CloudEvent. -func (c *CloudEvent) UnmarshalJSON(data []byte) error { - var rawMsg map[string]json.RawMessage - if err := json.Unmarshal(data, &rawMsg); err != nil { - return fmt.Errorf("unmarshalling type %T: %v", c, err) - } - for key, val := range rawMsg { - var err error - switch key { - case "data": - err = unpopulate(val, "Data", &c.Data) - delete(rawMsg, key) - case "data_base64": - err = runtime.DecodeByteArray(string(val), &c.DataBase64, runtime.Base64StdFormat) - delete(rawMsg, key) - case "datacontenttype": - err = unpopulate(val, "DataContentType", &c.DataContentType) - delete(rawMsg, key) - case "dataschema": - err = unpopulate(val, "DataSchema", &c.DataSchema) - delete(rawMsg, key) - case "id": - err = unpopulate(val, "ID", &c.ID) - delete(rawMsg, key) - case "source": - err = unpopulate(val, "Source", &c.Source) - delete(rawMsg, key) - case "specversion": - err = unpopulate(val, "SpecVersion", &c.SpecVersion) - delete(rawMsg, key) - case "subject": - err = unpopulate(val, "Subject", &c.Subject) - delete(rawMsg, key) - case "time": - err = unpopulateTimeRFC3339(val, "Time", &c.Time) - delete(rawMsg, key) - case "type": - err = unpopulate(val, "Type", &c.Type) - delete(rawMsg, key) - } - if err != nil { - return fmt.Errorf("unmarshalling type %T: %v", c, err) - } - } - return nil -} - // MarshalJSON implements the json.Marshaller interface for type FailedLockToken. func (f FailedLockToken) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any) @@ -491,26 +325,6 @@ func populate(m map[string]any, k string, v any) { } } -func populateAny(m map[string]any, k string, v any) { - if v == nil { - return - } else if azcore.IsNullValue(v) { - m[k] = nil - } else { - m[k] = v - } -} - -func populateByteArray(m map[string]any, k string, b []byte, f runtime.Base64Encoding) { - if azcore.IsNullValue(b) { - m[k] = nil - } else if len(b) == 0 { - return - } else { - m[k] = runtime.EncodeByteArray(b, f) - } -} - func unpopulate(data json.RawMessage, fn string, v any) error { if data == nil { return nil diff --git a/sdk/messaging/azeventgrid/response_types.go b/sdk/messaging/azeventgrid/response_types.go index 723f70baba03..12307db4989d 100644 --- a/sdk/messaging/azeventgrid/response_types.go +++ b/sdk/messaging/azeventgrid/response_types.go @@ -1,5 +1,3 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. //go:build go1.18 // +build go1.18 diff --git a/sdk/messaging/azeventgrid/shared_test.go b/sdk/messaging/azeventgrid/shared_test.go index 1e50ff2cc986..d13ff747d80f 100644 --- a/sdk/messaging/azeventgrid/shared_test.go +++ b/sdk/messaging/azeventgrid/shared_test.go @@ -17,6 +17,7 @@ import ( "testing" "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/messaging" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/internal/recording" @@ -37,6 +38,9 @@ type testVars struct { Topic string Subscription string + // KeyLogPath is the value of environment "SSLKEYLOGFILE_TEST", which + // points to a file on disk where we'll write the TLS pre-master-secret. + // This is useful if you want to trace parts of this test using Wireshark. KeyLogPath string } @@ -93,25 +97,31 @@ func newClientWrapper(t *testing.T, opts *clientWrapperOptions) clientWrapper { } if recording.GetRecordMode() == recording.LiveMode { - keyLogWriter, err := os.OpenFile(tv.KeyLogPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0777) - require.NoError(t, err) + if tv.KeyLogPath != "" { + keyLogWriter, err := os.OpenFile(tv.KeyLogPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0777) + require.NoError(t, err) - t.Cleanup(func() { keyLogWriter.Close() }) + t.Cleanup(func() { keyLogWriter.Close() }) - tp := http.DefaultTransport.(*http.Transport).Clone() - tp.TLSClientConfig = &tls.Config{ - KeyLogWriter: keyLogWriter, - } + tp := http.DefaultTransport.(*http.Transport).Clone() + tp.TLSClientConfig = &tls.Config{ + KeyLogWriter: keyLogWriter, + } - httpClient := &http.Client{Transport: tp} + httpClient := &http.Client{Transport: tp} - tmpClient, err := azeventgrid.NewClientWithSharedKeyCredential(tv.Endpoint, tv.Key, &azeventgrid.ClientOptions{ - ClientOptions: azcore.ClientOptions{ - Transport: httpClient, - }, - }) - require.NoError(t, err) - client = tmpClient + tmpClient, err := azeventgrid.NewClientWithSharedKeyCredential(tv.Endpoint, tv.Key, &azeventgrid.ClientOptions{ + ClientOptions: azcore.ClientOptions{ + Transport: httpClient, + }, + }) + require.NoError(t, err) + client = tmpClient + } else { + tmpClient, err := azeventgrid.NewClientWithSharedKeyCredential(tv.Endpoint, tv.Key, nil) + require.NoError(t, err) + client = tmpClient + } purgePreviousEvents(t, client, tv) } else { @@ -149,6 +159,9 @@ func newRecordingTransporter(t *testing.T, testVars testVars) policy.Transporter err = recording.AddURISanitizer(fakeTestVars.Subscription, testVars.Subscription, nil) require.NoError(t, err) + err = recording.AddGeneralRegexSanitizer(`"time": "2023-06-17T00:33:32Z"`, `"time":".+?"`, nil) + require.NoError(t, err) + err = recording.AddGeneralRegexSanitizer( `"id":"00000000-0000-0000-0000-000000000000"`, `"id":"[^"]+"`, nil) @@ -169,11 +182,29 @@ func newRecordingTransporter(t *testing.T, testVars testVars) policy.Transporter `"succeededLockTokens":\s*\[\s*"[^"]+"\s*\]`, nil) require.NoError(t, err) + err = recording.AddGeneralRegexSanitizer( + `"succeededLockTokens": ["fake-lock-token", "fake-lock-token", "fake-lock-token"]`, + `"succeededLockTokens":\s*`+ + `\[`+ + `(\s*"[^"]+"\s*\,){2}`+ + `\s*"[^"]+"\s*`+ + `\]`, nil) + require.NoError(t, err) + err = recording.AddGeneralRegexSanitizer( `"lockTokens": ["fake-lock-token", "fake-lock-token"]`, `"lockTokens":\s*\[\s*"[^"]+"\s*\,\s*"[^"]+"\s*\]`, nil) require.NoError(t, err) + err = recording.AddGeneralRegexSanitizer( + `"lockTokens": ["fake-lock-token", "fake-lock-token", "fake-lock-token"]`, + `"lockTokens":\s*`+ + `\[`+ + `(\s*"[^"]+"\s*\,){2}`+ + `\s*"[^"]+"\s*`+ + `\]`, nil) + require.NoError(t, err) + t.Cleanup(func() { err := recording.Stop(t, nil) require.NoError(t, err) @@ -182,17 +213,14 @@ func newRecordingTransporter(t *testing.T, testVars testVars) policy.Transporter return transport } -func requireEqualCloudEvent(t *testing.T, expected *azeventgrid.CloudEvent, actual *azeventgrid.CloudEvent) { +func requireEqualCloudEvent(t *testing.T, expected messaging.CloudEvent, actual messaging.CloudEvent) { t.Helper() require.NotEmpty(t, actual.ID, "ID is not empty") require.NotEmpty(t, actual.SpecVersion, "SpecVersion is not empty") expected.ID = actual.ID - - if expected.SpecVersion == nil { - expected.SpecVersion = actual.SpecVersion - } + expected.Time = actual.Time require.Equal(t, actual, expected) } diff --git a/sdk/messaging/azeventgrid/test-resources.bicep b/sdk/messaging/azeventgrid/test-resources.bicep index 3f20c0681e00..7297d1b5ba56 100644 --- a/sdk/messaging/azeventgrid/test-resources.bicep +++ b/sdk/messaging/azeventgrid/test-resources.bicep @@ -53,7 +53,7 @@ resource ns_testtopic1_testsubscription1 'Microsoft.EventGrid/namespaces/topics/ // https://learn.microsoft.com/en-us/rest/api/eventgrid/controlplane-version2023-06-01-preview/namespaces/list-shared-access-keys?tabs=HTTP output EVENTGRID_KEY string = listKeys(resourceId('Microsoft.EventGrid/namespaces', namespaceName), '2023-06-01-preview').key1 // TODO: get this formatted properly -output EVENTGRID_ENDPOINT string= 'https://${ns_resource.properties.topicsConfiguration.hostname}' +output EVENTGRID_ENDPOINT string = 'https://${ns_resource.properties.topicsConfiguration.hostname}' output EVENTGRID_TOPIC string = topicName output EVENTGRID_SUBSCRIPTION string = subscriptionName diff --git a/sdk/messaging/azeventgrid/time_rfc3339.go b/sdk/messaging/azeventgrid/time_rfc3339.go index dd6f013810cb..f8fbc9ae9dfc 100644 --- a/sdk/messaging/azeventgrid/time_rfc3339.go +++ b/sdk/messaging/azeventgrid/time_rfc3339.go @@ -1,5 +1,3 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. //go:build go1.18 // +build go1.18 @@ -14,11 +12,12 @@ package azeventgrid import ( "encoding/json" "fmt" - "github.com/Azure/azure-sdk-for-go/sdk/azcore" "reflect" "regexp" "strings" "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" ) const (