From ebff1eb203f475d2911a891ddd3fb8934244cf06 Mon Sep 17 00:00:00 2001 From: Niveathika Date: Wed, 6 Dec 2023 13:43:58 +0530 Subject: [PATCH 01/10] Add mock service for gmail endpoint --- ballerina/modules/mock/openapi_service.bal | 701 +++++++++++++++++++++ ballerina/modules/mock/types.bal | 257 ++++++++ 2 files changed, 958 insertions(+) create mode 100644 ballerina/modules/mock/openapi_service.bal create mode 100644 ballerina/modules/mock/types.bal diff --git a/ballerina/modules/mock/openapi_service.bal b/ballerina/modules/mock/openapi_service.bal new file mode 100644 index 00000000..370c302c --- /dev/null +++ b/ballerina/modules/mock/openapi_service.bal @@ -0,0 +1,701 @@ +// AUTO-GENERATED FILE. +// This file is auto-generated by the Ballerina OpenAPI tool. +import ballerina/http; + +listener http:Listener ep0 = new (9090, config = {host: "localhost"}); + +service /gmail/v1 on ep0 { + resource function get users/[string userId]/drafts(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, boolean? includeSpamTrash, int? maxResults, string? pageToken, + string? q) + returns ListDraftsResponse { + Draft draft = { + id: "1", + message: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + ListDraftsResponse response = {drafts: [draft]}; + return response; + } + + resource function post users/[string userId]/drafts(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, @http:Payload Draft payload) + returns OkDraft { + return { + body: { + id: "1", + message: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value updated"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + } + }; + } + + resource function post users/[string userId]/drafts/send(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, @http:Payload Draft payload) + returns OkMessage { + return { + body: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value updated"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + } + + resource function get users/[string userId]/drafts/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, "minimal"|"full"|"raw"|"metadata"? format) + returns Draft { + return { + id: "1", + message: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + } + + resource function put users/[string userId]/drafts/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, @http:Payload Draft payload) + returns Draft { + return { + id: "1", + message: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value updated"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + } + + resource function delete users/[string userId]/drafts/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType) + returns http:Ok { + return http:OK; + } + + resource function get users/[string userId]/history(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, + ("messageAdded"|"messageDeleted"|"labelAdded"|"labelRemoved")[]? historyTypes, + string? labelId, int? maxResults, string? pageToken, string? startHistoryId) + returns ListHistoryResponse { + return { + history: [ + { + id: "1", + messages: [ + { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + ] + } + ], + historyId: "1", + nextPageToken: "nextPageToken" + }; + } + + resource function get users/[string userId]/labels(Xgafv? \$\.xgafv, string? access_token, Alt? alt, string? callback, + string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType) + returns ListLabelsResponse { + return { + labels: [ + { + id: "1", + name: "CUSTOMER" + } + ] + }; + } + + resource function post users/[string userId]/labels(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, @http:Payload Label payload) + returns OkLabel { + return { + body: { + id: "1", + name: "CUSTOMER" + } + }; + } + + resource function get users/[string userId]/labels/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType) + returns Label { + return { + id: "1", + name: "CUSTOMER" + }; + } + + resource function put users/[string userId]/labels/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, @http:Payload Label payload) + returns Label { + return { + id: "1", + name: "CUSTOMER" + }; + } + + resource function delete users/[string userId]/labels/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType) + returns http:Ok { + return http:OK; + } + + resource function patch users/[string userId]/labels/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, @http:Payload Label payload) + returns Label { + return { + id: "1", + name: "CUSTOMER PATCHED" + }; + } + + resource function get users/[string userId]/messages(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, boolean? includeSpamTrash, string[]? labelIds, int? maxResults, + string? pageToken, string? q) + returns ListMessagesResponse { + return { + messages: [ + { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + ], + nextPageToken: "nextPageToken" + }; + } + + resource function post users/[string userId]/messages(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, boolean? deleted, "receivedTime"|"dateHeader"? internalDateSource, + @http:Payload Message payload) + returns OkMessage { + return { + body: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + } + + resource function post users/[string userId]/messages/batchDelete(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, @http:Payload BatchDeleteMessagesRequest payload) + returns http:Ok { + return http:OK; + } + + resource function post users/[string userId]/messages/batchModify(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, @http:Payload BatchModifyMessagesRequest payload) + returns http:Ok { + return http:OK; + } + + resource function post users/[string userId]/messages/'import(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, boolean? deleted, "receivedTime"|"dateHeader"? internalDateSource, + boolean? neverMarkSpam, boolean? processForCalendar, @http:Payload Message payload) + returns OkMessage { + return { + body: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + } + + resource function post users/[string userId]/messages/send(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, @http:Payload Message payload) + returns OkMessage { + return { + body: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + } + + resource function get users/[string userId]/messages/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, "minimal"|"full"|"raw"|"metadata"? format, + string[]? metadataHeaders) + returns Message { + return { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + }; + } + + resource function delete users/[string userId]/messages/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType) + returns http:Ok { + return http:OK; + } + + resource function post users/[string userId]/messages/[string id]/modify(Xgafv? \$\.xgafv, string? access_token, + Alt? alt, string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, + string? quotaUser, string? upload_protocol, string? uploadType, @http:Payload ModifyMessageRequest payload) + returns OkMessage { + return { + body: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + } + + resource function post users/[string userId]/messages/[string id]/trash(Xgafv? \$\.xgafv, string? access_token, + Alt? alt, string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, + string? quotaUser, string? upload_protocol, string? uploadType) + returns OkMessage { + return { + body: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + } + + resource function post users/[string userId]/messages/[string id]/untrash(Xgafv? \$\.xgafv, string? access_token, + Alt? alt, string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, + string? quotaUser, string? upload_protocol, string? uploadType) + returns OkMessage { + return { + body: { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet", + historyId: "1", + payload: { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [ + { + partId: "1", + mimeType: "text/plain", + filename: "filename", + headers: [{name: "name", value: "value"}], + body: {size: 1, data: "data"}, + parts: [] + } + ] + } + } + }; + } + + resource function get users/[string userId]/messages/[string messageId]/attachments/[string id](Xgafv? \$\.xgafv, + string? access_token, Alt? alt, string? callback, string? fields, string? 'key, string? oauth_token, + boolean? prettyPrint, string? quotaUser, string? upload_protocol, string? uploadType) + returns MessagePartBody { + return { + attachmentId: "1", + size: 1, + data: "data" + }; + } + + resource function get users/[string userId]/profile(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType) + returns Profile { + return { + emailAddress: "emailAddress", + messagesTotal: 1, + threadsTotal: 1, + historyId: "1" + }; + } + + resource function get users/[string userId]/threads(Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, boolean? includeSpamTrash, string[]? labelIds, int? maxResults, + string? pageToken, string? q) + returns ListThreadsResponse { + return { + threads: [ + { + id: "1", + historyId: "1", + messages: [ + { + id: "1", + threadId: "1" + } + ] + } + ], + nextPageToken: "nextPageToken" + }; + } + + resource function get users/[string userId]/threads/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType, "full"|"metadata"|"minimal"? format, string[]? metadataHeaders) + returns MailThread { + return { + id: "1", + historyId: "1", + messages: [ + { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet" + } + ] + }; + } + + resource function delete users/[string userId]/threads/[string id](Xgafv? \$\.xgafv, string? access_token, Alt? alt, + string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, string? quotaUser, + string? upload_protocol, string? uploadType) + returns http:Ok { + return http:OK; + } + + resource function post users/[string userId]/threads/[string id]/modify(Xgafv? \$\.xgafv, string? access_token, + Alt? alt, string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, + string? quotaUser, string? upload_protocol, string? uploadType, @http:Payload ModifyThreadRequest payload) + returns OkMailThread { + return { + body: { + id: "1", + historyId: "1", + messages: [ + { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet" + } + ] + } + }; + } + + resource function post users/[string userId]/threads/[string id]/trash(Xgafv? \$\.xgafv, string? access_token, + Alt? alt, string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, + string? quotaUser, string? upload_protocol, string? uploadType) + returns OkMailThread { + return { + body: { + id: "1", + historyId: "1", + messages: [ + { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet" + } + ] + } + }; + } + + resource function post users/[string userId]/threads/[string id]/untrash(Xgafv? \$\.xgafv, string? access_token, + Alt? alt, string? callback, string? fields, string? 'key, string? oauth_token, boolean? prettyPrint, + string? quotaUser, string? upload_protocol, string? uploadType) + returns OkMailThread { + return { + body: { + id: "1", + historyId: "1", + messages: [ + { + id: "1", + threadId: "1", + labelIds: ["CUSTOMER"], + snippet: "snippet" + } + ] + } + }; + } +} diff --git a/ballerina/modules/mock/types.bal b/ballerina/modules/mock/types.bal new file mode 100644 index 00000000..19f70cd9 --- /dev/null +++ b/ballerina/modules/mock/types.bal @@ -0,0 +1,257 @@ +// AUTO-GENERATED FILE. +// This file is auto-generated by the Ballerina OpenAPI tool. +import ballerina/http; + +public type OkDraft record {| + *http:Ok; + Draft body; +|}; + +public type OkMessage record {| + *http:Ok; + Message body; +|}; + +public type OkMailThread record {| + *http:Ok; + MailThread body; +|}; + +public type OkLabel record {| + *http:Ok; + Label body; +|}; + +public type HistoryLabelAdded record { + # Label IDs added to the message. + string[] labelIds?; + # An email message. + Message message?; +}; + +public type HistoryMessageDeleted record { + # An email message. + Message message?; +}; + +public type ListDraftsResponse record { + # List of drafts. Note that the `Message` property in each `Draft` resource only contains an `id` and a `threadId`. The messages.get method can fetch additional message details. + Draft[] drafts?; + # Token to retrieve the next page of results in the list. + string nextPageToken?; + # Estimated total number of results. + int resultSizeEstimate?; +}; + +# An email message. +public type Message record { + # The ID of the last history record that modified this message. + string historyId?; + # The immutable ID of the message. + string id?; + # The internal message creation timestamp (epoch ms), which determines ordering in the inbox. For normal SMTP-received email, this represents the time the message was originally accepted by Google, which is more reliable than the `Date` header. However, for API-migrated mail, it can be configured by client to be based on the `Date` header. + string internalDate?; + # List of IDs of labels applied to this message. + string[] labelIds?; + # A single MIME message part. + MessagePart payload?; + # The entire email message in an RFC 2822 formatted and base64url encoded string. Returned in `messages.get` and `drafts.get` responses when the `format=RAW` parameter is supplied. + string raw?; + # Estimated size in bytes of the message. + int:Signed32 sizeEstimate?; + # A short part of the message text. + string snippet?; + # The ID of the thread the message belongs to. To add a message or draft to a thread, the following criteria must be met: 1. The requested `threadId` must be specified on the `Message` or `Draft.Message` you supply with your request. 2. The `References` and `In-Reply-To` headers must be set in compliance with the [RFC 2822](https://tools.ietf.org/html/rfc2822) standard. 3. The `Subject` headers must match. + string threadId?; +}; + +# A collection of messages representing a conversation. +public type MailThread record { + # The ID of the last history record that modified this thread. + string historyId?; + # The unique ID of the thread. + string id?; + # The list of messages in the thread. + Message[] messages?; + # A short part of the message text. + string snippet?; +}; + +public type BatchModifyMessagesRequest record { + # A list of label IDs to add to messages. + string[] addLabelIds?; + # The IDs of the messages to modify. There is a limit of 1000 ids per request. + string[] ids?; + # A list of label IDs to remove from messages. + string[] removeLabelIds?; +}; + +# Data format for response. +public type Alt "json"|"media"|"proto"; + +# Labels are used to categorize messages and threads within the user's mailbox. The maximum number of labels supported for a user's mailbox is 10,000. +public type Label record { + # The color to assign to the label. Color is only available for labels that have their `type` set to `user`. + LabelColor color?; + # The immutable ID of the label. + string id?; + # The visibility of the label in the label list in the Gmail web interface. + "labelShow"|"labelShowIfUnread"|"labelHide" labelListVisibility?; + # The visibility of messages with this label in the message list in the Gmail web interface. + "show"|"hide" messageListVisibility?; + # The total number of messages with the label. + int:Signed32 messagesTotal?; + # The number of unread messages with the label. + int:Signed32 messagesUnread?; + # The display name of the label. + string name?; + # The total number of threads with the label. + int:Signed32 threadsTotal?; + # The number of unread threads with the label. + int:Signed32 threadsUnread?; + # The owner type for the label. User labels are created by the user and can be modified and deleted by the user and can be applied to any message or thread. System labels are internally created and cannot be added, modified, or deleted. System labels may be able to be applied to or removed from messages and threads under some circumstances but this is not guaranteed. For example, users can apply and remove the `INBOX` and `UNREAD` labels from messages and threads, but cannot apply or remove the `DRAFTS` or `SENT` labels from messages or threads. + "system"|"user" 'type?; +}; + +# V1 error format. +public type Xgafv "1"|"2"; + +# A record of a change to the user's mailbox. Each history change may affect multiple messages in multiple ways. +public type History record { + # The mailbox sequence ID. + string id?; + # Labels added to messages in this history record. + HistoryLabelAdded[] labelsAdded?; + # Labels removed from messages in this history record. + HistoryLabelRemoved[] labelsRemoved?; + # List of messages changed in this history record. The fields for specific change types, such as `messagesAdded` may duplicate messages in this field. We recommend using the specific change-type fields instead of this. + Message[] messages?; + # Messages added to the mailbox in this history record. + HistoryMessageAdded[] messagesAdded?; + # Messages deleted (not Trashed) from the mailbox in this history record. + HistoryMessageDeleted[] messagesDeleted?; +}; + +public type ListLabelsResponse record { + # List of labels. Note that each label resource only contains an `id`, `name`, `messageListVisibility`, `labelListVisibility`, and `type`. The labels.get method can fetch additional label details. + Label[] labels?; +}; + +# Profile for a Gmail user. +public type Profile record { + # The user's email address. + string emailAddress?; + # The ID of the mailbox's current history record. + string historyId?; + # The total number of messages in the mailbox. + int:Signed32 messagesTotal?; + # The total number of threads in the mailbox. + int:Signed32 threadsTotal?; +}; + +# The color to assign to the label. Color is only available for labels that have their `type` set to `user`. +public type LabelColor record { + # The background color represented as hex string #RRGGBB (ex #000000). This field is required in order to set the color of a label. Only the following predefined set of color values are allowed: \#000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, \#fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, \#f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, \#efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, \#e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, \#cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, \#ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, \#822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c \#464646, #e7e7e7, #0d3472, #b6cff5, #0d3b44, #98d7e4, #3d188e, #e3d7ff, \#711a36, #fbd3e0, #8a1c0a, #f2b2a8, #7a2e0b, #ffc8af, #7a4706, #ffdeb5, \#594c05, #fbe983, #684e07, #fdedc1, #0b4f30, #b3efd3, #04502e, #a2dcc1, \#c2c2c2, #4986e7, #2da2bb, #b99aff, #994a64, #f691b2, #ff7537, #ffad46, \#662e37, #ebdbde, #cca6ac, #094228, #42d692, #16a765 + string backgroundColor?; + # The text color of the label, represented as hex string. This field is required in order to set the color of a label. Only the following predefined set of color values are allowed: \#000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, \#fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, \#f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, \#efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, \#e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, \#cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, \#ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, \#822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c \#464646, #e7e7e7, #0d3472, #b6cff5, #0d3b44, #98d7e4, #3d188e, #e3d7ff, \#711a36, #fbd3e0, #8a1c0a, #f2b2a8, #7a2e0b, #ffc8af, #7a4706, #ffdeb5, \#594c05, #fbe983, #684e07, #fdedc1, #0b4f30, #b3efd3, #04502e, #a2dcc1, \#c2c2c2, #4986e7, #2da2bb, #b99aff, #994a64, #f691b2, #ff7537, #ffad46, \#662e37, #ebdbde, #cca6ac, #094228, #42d692, #16a765 + string textColor?; +}; + +public type MessagePartHeader record { + # The name of the header before the `:` separator. For example, `To`. + string name?; + # The value of the header after the `:` separator. For example, `someuser@example.com`. + string value?; +}; + +# A single MIME message part. +public type MessagePart record { + # The body of a single MIME message part. + MessagePartBody body?; + # The filename of the attachment. Only present if this message part represents an attachment. + string filename?; + # List of headers on this message part. For the top-level message part, representing the entire message payload, it will contain the standard RFC 2822 email headers such as `To`, `From`, and `Subject`. + MessagePartHeader[] headers?; + # The MIME type of the message part. + string mimeType?; + # The immutable ID of the message part. + string partId?; + # The child MIME message parts of this part. This only applies to container MIME message parts, for example `multipart/*`. For non- container MIME message part types, such as `text/plain`, this field is empty. For more information, see RFC 1521. + MessagePart[] parts?; +}; + +public type HistoryLabelRemoved record { + # Label IDs removed from the message. + string[] labelIds?; + # An email message. + Message message?; +}; + +public type ListThreadsResponse record { + # Page token to retrieve the next page of results in the list. + string nextPageToken?; + # Estimated total number of results. + int resultSizeEstimate?; + # List of threads. Note that each thread resource does not contain a list of `messages`. The list of `messages` for a given thread can be fetched using the threads.get method. + MailThread[] threads?; +}; + +# A draft email in the user's mailbox. +public type Draft record { + # The immutable ID of the draft. + string id?; + # An email message. + Message message?; +}; + +public type ListMessagesResponse record { + # List of messages. Note that each message resource contains only an `id` and a `threadId`. Additional message details can be fetched using the messages.get method. + Message[] messages?; + # Token to retrieve the next page of results in the list. + string nextPageToken?; + # Estimated total number of results. + int resultSizeEstimate?; +}; + +public type ListHistoryResponse record { + # List of history records. Any `messages` contained in the response will typically only have `id` and `threadId` fields populated. + History[] history?; + # The ID of the mailbox's current history record. + string historyId?; + # Page token to retrieve the next page of results in the list. + string nextPageToken?; +}; + +public type ModifyMessageRequest record { + # A list of IDs of labels to add to this message. You can add up to 100 labels with each update. + string[] addLabelIds?; + # A list IDs of labels to remove from this message. You can remove up to 100 labels with each update. + string[] removeLabelIds?; +}; + +public type BatchDeleteMessagesRequest record { + # The IDs of the messages to delete. + string[] ids?; +}; + +# The body of a single MIME message part. +public type MessagePartBody record { + # When present, contains the ID of an external attachment that can be retrieved in a separate `messages.attachments.get` request. When not present, the entire content of the message part body is contained in the data field. + string attachmentId?; + # The body data of a MIME message part as a base64url encoded string. May be empty for MIME container types that have no message body or when the body data is sent as a separate attachment. An attachment ID is present if the body data is contained in a separate attachment. + string data?; + # Number of bytes for the message part data (encoding notwithstanding). + int:Signed32 size?; +}; + +public type ModifyThreadRequest record { + # A list of IDs of labels to add to this thread. You can add up to 100 labels with each update. + string[] addLabelIds?; + # A list of IDs of labels to remove from this thread. You can remove up to 100 labels with each update. + string[] removeLabelIds?; +}; + +public type HistoryMessageAdded record { + # An email message. + Message message?; +}; From 8c74bea677792c52d3f234c5190757e04b19786d Mon Sep 17 00:00:00 2001 From: Niveathika Date: Wed, 6 Dec 2023 13:45:54 +0530 Subject: [PATCH 02/10] Add dummy sts service --- ballerina/modules/mock/sts_service.bal | 61 ++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 ballerina/modules/mock/sts_service.bal diff --git a/ballerina/modules/mock/sts_service.bal b/ballerina/modules/mock/sts_service.bal new file mode 100644 index 00000000..20304804 --- /dev/null +++ b/ballerina/modules/mock/sts_service.bal @@ -0,0 +1,61 @@ +// Copyright (c) 2023, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +import ballerina/http; +import ballerina/log; + +configurable int HTTP_SERVER_PORT = 9444; +configurable int TOKEN_VALIDITY_PERIOD = 100; // in seconds + +listener http:Listener sts = new (HTTP_SERVER_PORT); + +service /oauth2 on sts { + + function init() { + log:printInfo("STS started on port: " + HTTP_SERVER_PORT.toString() + " (HTTP)"); + } + + // This issues an access token with reference to the received grant type (client credentials, password and refresh token grant type). + resource function post token(http:Request req) returns json|http:Unauthorized|http:BadRequest|http:InternalServerError { + json response = { + "access_token": "asdadadsadadada", + "token_type": "example", + "expires_in": TOKEN_VALIDITY_PERIOD, + "example_parameter": "example_value" + }; + return response; + } + + resource function post introspect(http:Request req) returns json|http:Unauthorized|http:BadRequest { + json response = { + "active": true, + "scope": "read write dolphin", + "client_id": "l238j323ds-23ij4", + "username": "jdoe", + "token_type": "token_type", + "exp": TOKEN_VALIDITY_PERIOD, + "iat": 1419350238, + "nbf": 1419350238, + "sub": "Z5O3upPC88QrAjx00dis", + "aud": "https://protected.example.net/resource", + "iss": "https://server.example.com/", + "jti": "JlbmMiOiJBMTI4Q0JDLUhTMjU2In", + "extension_field": "twenty-seven", + "scp": "admin" + }; + return response; + } + +} From b9d134d0e64c0c1aace8ee5d086fd8c07b446c0d Mon Sep 17 00:00:00 2001 From: Niveathika Date: Thu, 7 Dec 2023 14:17:08 +0530 Subject: [PATCH 03/10] Add test cases using mock server --- ballerina/modules/mock/openapi_service.bal | 22 +-- ballerina/tests/test.bal | 212 +++++++++------------ ballerina/tests/test_w_mock_server.bal | 174 +++++++++++++++++ 3 files changed, 263 insertions(+), 145 deletions(-) create mode 100644 ballerina/tests/test_w_mock_server.bal diff --git a/ballerina/modules/mock/openapi_service.bal b/ballerina/modules/mock/openapi_service.bal index 370c302c..440aa94b 100644 --- a/ballerina/modules/mock/openapi_service.bal +++ b/ballerina/modules/mock/openapi_service.bal @@ -50,27 +50,7 @@ service /gmail/v1 on ep0 { id: "1", message: { id: "1", - threadId: "1", - labelIds: ["CUSTOMER"], - snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value updated"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + threadId: "1" } } }; diff --git a/ballerina/tests/test.bal b/ballerina/tests/test.bal index c0957384..d88765d0 100644 --- a/ballerina/tests/test.bal +++ b/ballerina/tests/test.bal @@ -13,10 +13,8 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -import googleapis.gmail.oas; - -import ballerina/io; import ballerina/lang.runtime; +import ballerina/log; import ballerina/os; import ballerina/test; @@ -44,19 +42,31 @@ ConnectionConfig gmailConfig = { } }; -final Client gmailClient = check new (gmailConfig); +Client gmailClient = test:mock(Client); + +@test:BeforeGroups { + value: ["gmail"] +} +function initializeClientsForGmailServer() returns error? { + log:printInfo("Initializing client for gmail server"); + gmailClient = check new (gmailConfig); +} -@test:Config {} +@test:Config { + groups: ["gmail"] +} function testGmailGetProfile() returns error? { Profile profile = check gmailClient->/users/me/profile(); test:assertTrue(profile.emailAddress != "", msg = "/users/[userId]/profile failed. email address nil"); historyId = check profile.historyId.ensureType(string); } -@test:Config {} +@test:Config { + groups: ["gmail"] +} function testMessageInsert() returns error? { MessageRequest request = { - 'from: recipient, // Mail migration, mail reeived from receipent account + 'from: recipient, // Mail migration, mail received from recipient account subject: "Gmail insert test" }; Message message = check gmailClient->/users/me/messages.post(request); @@ -65,14 +75,16 @@ function testMessageInsert() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testMessageInsert] } -isolated function testListMessages() returns error? { +function testListMessages() returns error? { ListMessagesResponse msgPage = check gmailClient->/users/me/messages(); test:assertTrue(msgPage.messages is Message[], msg = "/users/[userId]/messages failed"); } @test:Config { + groups: ["gmail"], dependsOn: [testListMessages] } function testMessageBatchModify() returns error? { @@ -88,6 +100,7 @@ function testMessageBatchModify() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testMessageBatchModify] } function testMessageBatchDelete() returns error? { @@ -97,6 +110,7 @@ function testMessageBatchDelete() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testMessageBatchDelete] } function testPostMessage() returns error? { @@ -128,6 +142,7 @@ function testPostMessage() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testPostMessage] } function testGetMessageRawFormat() returns error? { @@ -136,6 +151,7 @@ function testGetMessageRawFormat() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testGetMessageRawFormat] } function testGetMessageFullFormat() returns error? { @@ -153,6 +169,7 @@ function testGetMessageFullFormat() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testGetMessageFullFormat] } function testMessageModify() returns error? { @@ -172,26 +189,39 @@ function testMessageModify() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testMessageModify] } function testMessageTrash() returns error? { _ = check gmailClient->/users/me/messages/[sentMessageId]/trash.post(); Message getMessage = check gmailClient->/users/me/messages/[sentMessageId]; - test:assertEquals(getMessage.labelIds, ["UNREAD", "TRASH", "SENT"], - msg = "/users/[userId]/messages/[sentMessageId]/trash failed TRASH label not added"); + string[]? labelIds = getMessage.labelIds; + if labelIds is string[] { + test:assertTrue(labelIds.filter(l => l == "TRASH").length() > 0, + msg = "/users/[userId]/messages/[sentMessageId]/trash failed TRASH label not added"); + } else { + test:assertFail("/users/[userId]/messages/[sentMessageId]/trash failed"); + } } @test:Config { + groups: ["gmail"], dependsOn: [testMessageTrash] } function testMessageUntrash() returns error? { _ = check gmailClient->/users/me/messages/[sentMessageId]/untrash.post(); Message getMessage = check gmailClient->/users/me/messages/[sentMessageId]; - test:assertEquals(getMessage.labelIds, ["UNREAD", "SENT"], - msg = "/users/[userId]/messages/[sentMessageId]/untrash failed TRASH label not removed"); + string[]? labelIds = getMessage.labelIds; + if labelIds is string[] { + test:assertTrue(labelIds.filter(l => l == "TRASH").length() == 0, + msg = "/users/[userId]/messages/[sentMessageId]/untrash failed TRASH label not removed"); + } else { + test:assertFail("/users/[userId]/messages/[sentMessageId]/untrash failed"); + } } @test:Config { + groups: ["gmail"], dependsOn: [testMessageUntrash] } function testGetAttachment() returns error? { @@ -200,6 +230,7 @@ function testGetAttachment() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testGetAttachment] } function testMessageDelete() returns error? { @@ -208,67 +239,8 @@ function testMessageDelete() returns error? { test:assertTrue(message is error, msg = "/users/[userId]/messages/[sentMessageId].delete failed. Msg not deleted"); } -@test:Config {} -isolated function testPayloadConversion() returns error? { - json response = check io:fileReadJson("tests/resources/messagebody.json"); - oas:MessagePart internalPayload = check response.fromJsonWithType(oas:MessagePart); - MessagePart convertedPayload = check convertOASMessagePartToMultipartMessageBody(internalPayload); - MessagePart messagePart = { - mimeType: "multipart/alternative", - filename: "", - headers: { - "Content-Type": "multipart/alternative; boundary=001a1142e23c551e8e05200b4be0" - }, - size: 0, - partId: "", - parts: [ - { - mimeType: "multipart/alternative", - filename: "", - headers: { - "Content-Type": "multipart/alternative; boundary=001a1142e23c551e8e05200b4be0" - }, - size: 0, - partId: "", - parts: [ - { - partId: "0.0", - mimeType: "text/plain", - filename: "", - headers: { - "Content-Type": "text/plain; charset=UTF-8" - }, - size: 9 - }, - { - partId: "0.1", - mimeType: "text/html", - filename: "", - headers: { - "Content-Type": "text/html; charset=UTF-8" - }, - size: 30 - } - ] - }, - { - partId: "1", - mimeType: "image/jpeg", - filename: "feelthebern.jpg", - headers: { - "Content-Type": "image/jpeg; name=\"feelthebern.jpg\"", - "Content-Disposition": "attachment; filename=\"feelthebern.jpg\"", - "Content-Transfer-Encoding": "base64", - "X-Attachment-Id": "f_ieq3ev0i0" - }, - size: 100446 - } - ] - }; - test:assertEquals(convertedPayload, messagePart, msg = "Payload conversion failed"); -} - @test:Config { + groups: ["gmail"], dependsOn: [testMessageDelete] } function createDraft() returns error? { @@ -285,14 +257,16 @@ function createDraft() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [createDraft] } -isolated function testListDrafts() returns error? { +function testListDrafts() returns error? { ListDraftsResponse draftListPage = check gmailClient->/users/me/drafts(); test:assertTrue(draftListPage.drafts is Draft[], msg = "/users/[userId]/drafts failed"); } @test:Config { + groups: ["gmail"], dependsOn: [testListDrafts] } function testSendDraft() returns error? { @@ -313,6 +287,7 @@ function testSendDraft() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testSendDraft] } function testGetDraft() returns error? { @@ -321,6 +296,7 @@ function testGetDraft() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testGetDraft] } function testPutDraft() returns error? { @@ -332,11 +308,13 @@ function testPutDraft() returns error? { } }); test:assertTrue(updatedDraft.id != "", msg = "/users/[userId]/drafts/[draftId] failed"); - Draft draft = check gmailClient->/users/me/drafts/[draftId]; - test:assertTrue(draft.message?.subject == "Gmail draft test updated", msg = "/users/[userId]/drafts/[draftId] failed"); + Draft draft = check gmailClient->/users/me/drafts/[draftId](format = "raw"); + test:assertTrue(draft.message?.raw.toString().includes("subject:Gmail draft test updated"), + msg = "/users/[userId]/drafts/[draftId] failed"); } @test:Config { + groups: ["gmail"], dependsOn: [testPutDraft] } function testDeleteDraft() returns error? { @@ -346,6 +324,7 @@ function testDeleteDraft() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testDeleteDraft] } function testListMailThreads() returns error? { @@ -362,6 +341,7 @@ function testListMailThreads() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testListMailThreads] } function testGetMailThread() returns error? { @@ -370,6 +350,7 @@ function testGetMailThread() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testGetMailThread] } function testModifyMailThread() returns error? { @@ -378,9 +359,9 @@ function testModifyMailThread() returns error? { }); test:assertTrue(mailThread.historyId != (), msg = "/users/[userId]/threads/[threadId]/modify failed"); MailThread getMailThread = check gmailClient->/users/me/threads/[threadId]; - Message[]? firstMesssage = getMailThread.messages; - if firstMesssage is Message[] { - string[]? labelIds = firstMesssage[0].labelIds; + Message[]? firstMessage = getMailThread.messages; + if firstMessage is Message[] { + string[]? labelIds = firstMessage[0].labelIds; if labelIds is string[] { test:assertTrue(labelIds.filter(l => l == "UNREAD").length() > 0, msg = "/users/[userId]/threads/[threadId]/modify failed"); @@ -393,38 +374,51 @@ function testModifyMailThread() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testModifyMailThread] } function testTrashMailThread() returns error? { MailThread mailThread = check gmailClient->/users/me/threads/[threadId]/trash.post(); test:assertTrue(mailThread.historyId != (), msg = "/users/[userId]/threads/[threadId]/trash failed"); MailThread getMailThread = check gmailClient->/users/me/threads/[threadId]; - Message[]? firstMesssage = getMailThread.messages; - if firstMesssage is Message[] { - test:assertEquals(firstMesssage[0].labelIds, ["UNREAD", "TRASH", "SENT"], - msg = "/users/[userId]/threads/[threadId]/trash failed TRASH label not added"); + Message[]? firstMessage = getMailThread.messages; + if firstMessage is Message[] { + string[]? labelIds = firstMessage[0].labelIds; + if labelIds is string[] { + test:assertTrue(labelIds.filter(l => l == "TRASH").length() > 0, + msg = "/users/[userId]/threads/[threadId]/trash failed TRASH label not added"); + } else { + test:assertFail("/users/[userId]/threads/[threadId]/trash failed"); + } } else { test:assertFail("Message not found"); } } @test:Config { + groups: ["gmail"], dependsOn: [testTrashMailThread] } function testUntrashMailThread() returns error? { MailThread mailThread = check gmailClient->/users/me/threads/[threadId]/untrash.post(); test:assertTrue(mailThread.historyId != (), msg = "/users/[userId]/threads/[threadId]/untrash failed"); MailThread getMailThread = check gmailClient->/users/me/threads/[threadId]; - Message[]? firstMesssage = getMailThread.messages; - if firstMesssage is Message[] { - test:assertEquals(firstMesssage[0].labelIds, ["UNREAD", "SENT"], - msg = "/users/[userId]/threads/[threadId]/untrash failed TRASH label not removed"); + Message[]? firstMessage = getMailThread.messages; + if firstMessage is Message[] { + string[]? labelIds = firstMessage[0].labelIds; + if labelIds is string[] { + test:assertTrue(labelIds.filter(l => l == "TRASH").length() == 0, + msg = "/users/[userId]/threads/[threadId]/untrash failed TRASH label not removed"); + } else { + test:assertFail("/users/[userId]/threads/[threadId]/untrash failed"); + } } else { test:assertFail("Message not found"); } } @test:Config { + groups: ["gmail"], dependsOn: [testUntrashMailThread] } function testDeleteMailThread() returns error? { @@ -434,6 +428,7 @@ function testDeleteMailThread() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testDeleteMailThread] } function testCreateNewLabel() returns error? { @@ -445,6 +440,7 @@ function testCreateNewLabel() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testCreateNewLabel] } function testListAllLabels() returns error? { @@ -453,6 +449,7 @@ function testListAllLabels() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testListAllLabels] } function testGetLabel() returns error? { @@ -461,6 +458,7 @@ function testGetLabel() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testGetLabel] } function testUpdateLabel() returns error? { @@ -474,6 +472,7 @@ function testUpdateLabel() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testUpdateLabel] } function testPatchLabel() returns error? { @@ -487,6 +486,7 @@ function testPatchLabel() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testPatchLabel] } function testDeleteLabel() returns error? { @@ -496,6 +496,7 @@ function testDeleteLabel() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testDeleteLabel, testGmailGetProfile] } function testListHistory() returns error? { @@ -504,6 +505,7 @@ function testListHistory() returns error? { } @test:Config { + groups: ["gmail"], dependsOn: [testListHistory] } function testReplyTo() returns error? { @@ -548,41 +550,3 @@ function testReplyTo() returns error? { } check gmailClient->/users/me/threads/[replyMessage.threadId].delete(); } - -@test:Config { -} -function testUrlDecodeFailure() returns error? { - oas:Message receivedMsg = { - threadId: "qweqweqdqd", - id: "saDSASDASDA", - raw: "ASDADSADADADADADAD" - }; - Message|error result = convertOASMessageToMessage(receivedMsg); - if result is error { - test:assertEquals(result.message(), "Returned message raw field is not a valid Base64 URL encoded value.", - msg = "Error decoding message"); - } else { - test:assertFail("Expected decoded error"); - } -} - -@test:Config { -} -function testAttachmentSendFailure() returns error? { - MessageRequest sendMsg = { - attachments: [ - { - name: "test.txt", - path: "asdadsa", - mimeType: "text/plain" - } - ] - }; - oas:Message|error result = convertMessageRequestToOASMessage(sendMsg); - if result is error { - test:assertEquals(result.message(), - "Unable to retrieve attachment: asdadsa", msg = "Error decoding message"); - } else { - test:assertFail("Expected decoded error"); - } -} diff --git a/ballerina/tests/test_w_mock_server.bal b/ballerina/tests/test_w_mock_server.bal new file mode 100644 index 00000000..96347520 --- /dev/null +++ b/ballerina/tests/test_w_mock_server.bal @@ -0,0 +1,174 @@ +// Copyright (c) 2023, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +import googleapis.gmail.mock as _; +import googleapis.gmail.oas; + +import ballerina/io; +import ballerina/log; +import ballerina/test; + +Client gmailClientForMockServer = test:mock(Client); + +@test:BeforeGroups { + value: ["mock"] +} +function initializeClientsForMockServer() returns error? { + log:printInfo("Initializing client for mock server"); + gmailClientForMockServer = check new ({ + timeout: 100000, + auth: { + refreshToken: "24f19603-8565-4b5f-a036-88a945e1f272", + clientId: "FlfJYKBD2c925h4lkycqNZlC2l4a", + clientSecret: "PJz0UhTJMrHOo68QQNpvnqAY_3Aa", + refreshUrl: "http://localhost:9444/oauth2/token" + } + }, + serviceUrl = "http://localhost:9090/gmail/v1" + ); +} + +@test:Config { + groups: ["mock"] +} +isolated function testPayloadConversion() returns error? { + json response = check io:fileReadJson("tests/resources/messagebody.json"); + oas:MessagePart internalPayload = check response.fromJsonWithType(oas:MessagePart); + MessagePart convertedPayload = check convertOASMessagePartToMultipartMessageBody(internalPayload); + MessagePart messagePart = { + mimeType: "multipart/alternative", + filename: "", + headers: { + "Content-Type": "multipart/alternative; boundary=001a1142e23c551e8e05200b4be0" + }, + size: 0, + partId: "", + parts: [ + { + mimeType: "multipart/alternative", + filename: "", + headers: { + "Content-Type": "multipart/alternative; boundary=001a1142e23c551e8e05200b4be0" + }, + size: 0, + partId: "", + parts: [ + { + partId: "0.0", + mimeType: "text/plain", + filename: "", + headers: { + "Content-Type": "text/plain; charset=UTF-8" + }, + size: 9 + }, + { + partId: "0.1", + mimeType: "text/html", + filename: "", + headers: { + "Content-Type": "text/html; charset=UTF-8" + }, + size: 30 + } + ] + }, + { + partId: "1", + mimeType: "image/jpeg", + filename: "feelthebern.jpg", + headers: { + "Content-Type": "image/jpeg; name=\"feelthebern.jpg\"", + "Content-Disposition": "attachment; filename=\"feelthebern.jpg\"", + "Content-Transfer-Encoding": "base64", + "X-Attachment-Id": "f_ieq3ev0i0" + }, + size: 100446 + } + ] + }; + test:assertEquals(convertedPayload, messagePart, msg = "Payload conversion failed"); +} + +@test:Config { + groups: ["mock"] +} +function testUrlDecodeFailure() returns error? { + oas:Message receivedMsg = { + threadId: "qweqweqdqd", + id: "saDSASDASDA", + raw: "ASDADSADADADADADAD" + }; + Message|error result = convertOASMessageToMessage(receivedMsg); + if result is error { + test:assertEquals(result.message(), "Returned message raw field is not a valid Base64 URL encoded value.", + msg = "Error decoding message"); + } else { + test:assertFail("Expected decoded error"); + } +} + +@test:Config { + groups: ["mock"] +} +function testAttachmentSendFailure() returns error? { + MessageRequest sendMsg = { + attachments: [ + { + name: "test.txt", + path: "asdadsa", + mimeType: "text/plain" + } + ] + }; + oas:Message|error result = convertMessageRequestToOASMessage(sendMsg); + if result is error { + test:assertEquals(result.message(), + "Unable to retrieve attachment: asdadsa", msg = "Error decoding message"); + } else { + test:assertFail("Expected decoded error"); + } +} + +@test:Config { + groups: ["mock"] +} +function testGmailGetProfileMock() returns error? { + Profile profile = check gmailClientForMockServer->/users/me/profile(); + test:assertTrue(profile.emailAddress != "", msg = "/users/[userId]/profile failed. email address nil"); +} + +@test:Config { + groups: ["mock"] +} +function testMessageDeleteMock() returns error? { + error? result = check gmailClientForMockServer->/users/me/messages/["123"].delete(); + test:assertTrue(result is (), msg = "/users/[userId]/messages/import failed"); +} + +@test:Config { + groups: ["mock"] +} +function createDraftForMock() returns error? { + DraftRequest request = { + message: { + to: [recipient], + subject: "Gmail draft test", + bodyInText: "This is a draft" + } + }; + Draft draft = check gmailClientForMockServer->/users/me/drafts.post(request); + test:assertTrue(draft.id != "", msg = "/users/[userId]/drafts failed"); +} From e6bd5a842c0de7f505f38860e4471ef7089a118b Mon Sep 17 00:00:00 2001 From: Niveathika Date: Thu, 7 Dec 2023 14:26:43 +0530 Subject: [PATCH 04/10] Fix wording --- changelog.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 58488ee4..9db9ca20 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,6 @@ # Changelog -This file contains all the notable changes done to the Ballerina SQL package through the releases. + +This file contains all the notable changes done to the Ballerina `googleapis.gmail` package through the releases. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). From 546afb4d5c35dc66f7e30f0b56ce8afbf9ddf1d0 Mon Sep 17 00:00:00 2001 From: Niveathika Date: Thu, 7 Dec 2023 14:28:30 +0530 Subject: [PATCH 05/10] Ignore mock submodule for code coverage --- ballerina/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina/build.gradle b/ballerina/build.gradle index 37d953b6..90a36084 100644 --- a/ballerina/build.gradle +++ b/ballerina/build.gradle @@ -47,7 +47,7 @@ def stripBallerinaExtensionVersion(String extVersion) { ballerina { packageOrganization = packageOrg module = packageName - testCoverageParam = "--code-coverage --coverage-format=xml --excludes=\"modules/oas/**\"" + testCoverageParam = "--code-coverage --coverage-format=xml --excludes=\"modules/**/**\"" isConnector = true platform = "any" } From 603d05458df6073ec9e1ec63de99ada7171584c3 Mon Sep 17 00:00:00 2001 From: Niveathika Date: Thu, 7 Dec 2023 14:51:31 +0530 Subject: [PATCH 06/10] Ignore modules subfolder in code coverage --- codecov.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/codecov.yml b/codecov.yml index b675e7e7..ed396ab1 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,4 +1,5 @@ ignore: + - "ballerina/modules" - "examples" coverage: From e49207567400ce275b26566f69d1c18b711e1c0d Mon Sep 17 00:00:00 2001 From: Niveathika Date: Tue, 12 Dec 2023 13:14:04 +0530 Subject: [PATCH 07/10] Improve readme with test groups --- README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ebf258a9..5de234b2 100644 --- a/README.md +++ b/README.md @@ -188,25 +188,37 @@ Execute the commands below to build from the source. ./gradlew clean build -x test ``` -4. To debug package with a remote debugger: +4. To run tests against different environment: + + ```bash + ./gradlew clean test -Pgroups= + ``` + + Tip: The following groups of test cases are available. + Groups | Environment + ---| --- + mock | Mock server + gmail | Gmail API + +5. To debug package with a remote debugger: ```bash ./gradlew clean build -Pdebug= ``` -5. To debug with the Ballerina language: +6. To debug with the Ballerina language: ```bash ./gradlew clean build -PbalJavaDebug= ``` -6. Publish the generated artifacts to the local Ballerina Central repository: +7. Publish the generated artifacts to the local Ballerina Central repository: ```bash ./gradlew clean build -PpublishToLocalCentral=true ``` -7. Publish the generated artifacts to the Ballerina Central repository: +8. Publish the generated artifacts to the Ballerina Central repository: ```bash ./gradlew clean build -PpublishToCentral=true From e9cd455f9069ca39d6a9953a7bb07021c851b67b Mon Sep 17 00:00:00 2001 From: Niveathika Date: Tue, 12 Dec 2023 13:18:36 +0530 Subject: [PATCH 08/10] Use mock environment for tests --- .github/workflows/build-with-bal-test-graalvm.yml | 2 +- .github/workflows/ci.yml | 1 + .github/workflows/dev-stage-release.yml | 2 +- .github/workflows/pull-request.yml | 2 ++ .github/workflows/trivy-scan.yml | 2 +- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-with-bal-test-graalvm.yml b/.github/workflows/build-with-bal-test-graalvm.yml index da418d71..f18b6cd7 100644 --- a/.github/workflows/build-with-bal-test-graalvm.yml +++ b/.github/workflows/build-with-bal-test-graalvm.yml @@ -16,4 +16,4 @@ jobs: uses: ballerina-platform/ballerina-standard-library/.github/workflows/build-with-bal-test-graalvm-connector-template.yml@main secrets: inherit with: - additional-build-flags: "-x :googleapis.gmail-examples:build" + additional-build-flags: "-x :googleapis.gmail-examples:build -Pgroups=mock" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94b935e3..9668e20a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,3 +16,4 @@ jobs: secrets: inherit with: repo-name: module-ballerinax-googleapis.gmail + additional-test-flags: -Pgroups=mock diff --git a/.github/workflows/dev-stage-release.yml b/.github/workflows/dev-stage-release.yml index 6e2cdfbb..278274a9 100644 --- a/.github/workflows/dev-stage-release.yml +++ b/.github/workflows/dev-stage-release.yml @@ -19,4 +19,4 @@ jobs: secrets: inherit with: environment: ${{ github.event.inputs.environment }} - additional-publish-flags: "-x :googleapis.gmail-examples:build" + additional-publish-flags: "-x :googleapis.gmail-examples:build -Pgroups=mock" diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 5dda0198..0562be58 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -12,3 +12,5 @@ jobs: if: ${{ github.repository_owner == 'ballerina-platform' }} uses: ballerina-platform/ballerina-standard-library/.github/workflows/pr-build-connector-template.yml@main secrets: inherit + with: + additional-test-flags: -Pgroups=mock diff --git a/.github/workflows/trivy-scan.yml b/.github/workflows/trivy-scan.yml index 4c087a8f..9dfdb2ae 100644 --- a/.github/workflows/trivy-scan.yml +++ b/.github/workflows/trivy-scan.yml @@ -12,4 +12,4 @@ jobs: uses: ballerina-platform/ballerina-standard-library/.github/workflows/trivy-scan-template.yml@main secrets: inherit with: - additional-build-flags: "-x :googleapis.gmail-examples:build" + additional-build-flags: "-x :googleapis.gmail-examples:build -Pgroups=mock" From fba1063eb69727e698421f614f563855bf6c4237 Mon Sep 17 00:00:00 2001 From: Niveathika Date: Tue, 12 Dec 2023 15:41:37 +0530 Subject: [PATCH 09/10] Add testcases for mock environment --- ballerina/modules/mock/openapi_service.bal | 253 ++---------------- ballerina/modules/mock/sts_service.bal | 2 +- ballerina/tests/test_w_mock_server.bal | 282 ++++++++++++++++++++- 3 files changed, 295 insertions(+), 242 deletions(-) diff --git a/ballerina/modules/mock/openapi_service.bal b/ballerina/modules/mock/openapi_service.bal index 440aa94b..75f9eadb 100644 --- a/ballerina/modules/mock/openapi_service.bal +++ b/ballerina/modules/mock/openapi_service.bal @@ -17,24 +17,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; ListDraftsResponse response = {drafts: [draft]}; @@ -66,24 +49,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value updated"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; } @@ -99,24 +65,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; } @@ -132,24 +81,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value updated"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; } @@ -177,24 +109,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } ] } @@ -276,27 +191,7 @@ service /gmail/v1 on ep0 { messages: [ { id: "1", - threadId: "1", - labelIds: ["CUSTOMER"], - snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + threadId: "1" } ], nextPageToken: "nextPageToken" @@ -314,24 +209,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; } @@ -361,24 +239,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; } @@ -393,24 +254,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; } @@ -426,23 +270,7 @@ service /gmail/v1 on ep0 { labelIds: ["CUSTOMER"], snippet: "snippet", historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + raw: "" }; } @@ -463,24 +291,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; } @@ -493,26 +304,9 @@ service /gmail/v1 on ep0 { body: { id: "1", threadId: "1", - labelIds: ["CUSTOMER"], + labelIds: ["CUSTOMER", "TRASH"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; } @@ -527,24 +321,7 @@ service /gmail/v1 on ep0 { threadId: "1", labelIds: ["CUSTOMER"], snippet: "snippet", - historyId: "1", - payload: { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [ - { - partId: "1", - mimeType: "text/plain", - filename: "filename", - headers: [{name: "name", value: "value"}], - body: {size: 1, data: "data"}, - parts: [] - } - ] - } + historyId: "1" } }; } @@ -556,7 +333,7 @@ service /gmail/v1 on ep0 { return { attachmentId: "1", size: 1, - data: "data" + data: "aW1hZ2U=" }; } diff --git a/ballerina/modules/mock/sts_service.bal b/ballerina/modules/mock/sts_service.bal index 20304804..f20aa8f5 100644 --- a/ballerina/modules/mock/sts_service.bal +++ b/ballerina/modules/mock/sts_service.bal @@ -17,7 +17,7 @@ import ballerina/http; import ballerina/log; configurable int HTTP_SERVER_PORT = 9444; -configurable int TOKEN_VALIDITY_PERIOD = 100; // in seconds +configurable int TOKEN_VALIDITY_PERIOD = 10000; // in seconds listener http:Listener sts = new (HTTP_SERVER_PORT); diff --git a/ballerina/tests/test_w_mock_server.bal b/ballerina/tests/test_w_mock_server.bal index 96347520..f67f2b9a 100644 --- a/ballerina/tests/test_w_mock_server.bal +++ b/ballerina/tests/test_w_mock_server.bal @@ -150,21 +150,132 @@ function testGmailGetProfileMock() returns error? { test:assertTrue(profile.emailAddress != "", msg = "/users/[userId]/profile failed. email address nil"); } +@test:Config { + groups: ["mock"] +} +function testMessageModifyMock() returns error? { + Message msg = check gmailClientForMockServer->/users/me/messages/["123"]/modify.post( + { + addLabelIds: ["UNREAD"] + } + ); + test:assertTrue(msg.id != "", msg = "/users/[userId]/messages/[messageId]/modify failed UNREAD label not added"); +} + +@test:Config { + groups: ["mock"] +} +function testMessageTrashMock() returns error? { + Message msg = check gmailClientForMockServer->/users/me/messages/["123"]/trash.post(); + test:assertTrue(msg.historyId != "", msg = "/users/[userId]/messages/[messageId]/trash failed"); +} + +@test:Config { + groups: ["mock"] +} +function testMessageUntrashMock() returns error? { + Message msg = check gmailClientForMockServer->/users/me/messages/["123"]/untrash.post(); + test:assertTrue(msg.historyId != "", msg = "/users/[userId]/messages/[messageId]/untrash failed"); +} + +@test:Config { + groups: ["mock"] +} +function testMessageInsertMock() returns error? { + MessageRequest request = { + 'from: recipient, // Mail migration, mail received from recipient account + subject: "Gmail insert test" + }; + Message message = check gmailClientForMockServer->/users/me/messages.post(request); + test:assertTrue(message.id != "", msg = "/users/[userId]/messages/import failed"); +} + +@test:Config { + groups: ["mock"] +} +function testMessageImportMock() returns error? { + MessageRequest request = { + 'from: recipient, // Mail migration, mail received from recipient account + subject: "Gmail insert test" + }; + Message message = check gmailClientForMockServer->/users/me/messages/'import.post(request); + test:assertTrue(message.id != "", msg = "/users/[userId]/messages/import failed"); +} + +@test:Config { + groups: ["mock"] +} +function testListMessagesMock() returns error? { + ListMessagesResponse msgPage = check gmailClientForMockServer->/users/me/messages(); + test:assertTrue(msgPage.messages is Message[], msg = "/users/[userId]/messages failed"); +} + +@test:Config { + groups: ["mock"] +} +function testGetMessagesMock() returns error? { + Message msg = check gmailClientForMockServer->/users/me/messages/["qw1"](); + test:assertTrue(msg.id != "", msg = "/users/[userId]/messages failed"); +} + +@test:Config { + groups: ["mock"] +} +function testMessageBatchModifyMock() { + error? msg = gmailClientForMockServer->/users/me/messages/batchModify.post( + { + ids: ["123"], + addLabelIds: ["UNREAD"] + } + ); + test:assertTrue(msg is (), msg = "/users/[userId]/messages/batchModify failed"); +} + +@test:Config { + groups: ["mock"] +} +function testMessageBatchDeleteMock() returns error? { + error? result = gmailClientForMockServer->/users/me/messages/batchDelete.post({ids: ["123"]}); + test:assertTrue(result is (), msg = "/users/[userId]/messages/batchDelete failed"); +} + +@test:Config { + groups: ["mock"] +} +function testPostMessageMock() returns error? { + MessageRequest request = { + to: ["test@gmail.com"], + subject: "Test Gmail Revamp", + bodyInText: "This is text equivalent", + bodyInHtml: "

Welcome!

\"Test_image.jpeg\"
" + }; + Message message = check gmailClientForMockServer->/users/me/messages/send.post(request); + test:assertTrue(message.id != "", msg = "/users/[userId]/messages/send failed"); +} + +@test:Config { + groups: ["mock"] +} +function testGetAttachmentMock() returns error? { + Attachment attachment = check gmailClientForMockServer->/users/me/messages/["123"]/attachments/["123"]; + test:assertTrue(attachment.data != "", msg = "/users/[userId]/messages/[sentMessageId]/attachments/[attachmentId] failed"); +} + @test:Config { groups: ["mock"] } function testMessageDeleteMock() returns error? { - error? result = check gmailClientForMockServer->/users/me/messages/["123"].delete(); + error? result = gmailClientForMockServer->/users/me/messages/["123"].delete(); test:assertTrue(result is (), msg = "/users/[userId]/messages/import failed"); } @test:Config { groups: ["mock"] } -function createDraftForMock() returns error? { +function createDraftMock() returns error? { DraftRequest request = { message: { - to: [recipient], + to: ["test@gmail.com"], subject: "Gmail draft test", bodyInText: "This is a draft" } @@ -172,3 +283,168 @@ function createDraftForMock() returns error? { Draft draft = check gmailClientForMockServer->/users/me/drafts.post(request); test:assertTrue(draft.id != "", msg = "/users/[userId]/drafts failed"); } + +@test:Config { + groups: ["mock"] +} +function testListDraftsMock() returns error? { + ListDraftsResponse draftListPage = check gmailClientForMockServer->/users/me/drafts(); + test:assertTrue(draftListPage.drafts is Draft[], msg = "/users/[userId]/drafts failed"); +} + +@test:Config { + groups: ["mock"] +} +function testSendDraftMock() returns error? { + DraftRequest request = { + message: { + to: [recipient], + subject: "Gmail draft test" + } + }; + Message message = check gmailClientForMockServer->/users/me/drafts/send.post(request); + test:assertTrue(message.id != "", msg = "/users/[userId]/drafts failed"); +} + +@test:Config { + groups: ["mock"] +} +function testGetDraftMock() returns error? { + Draft draft = check gmailClientForMockServer->/users/me/drafts/["123"]; + test:assertTrue(draft.id != "", msg = "/users/[userId]/drafts/[draftId] failed"); +} + +@test:Config { + groups: ["mock"] +} +function testPutDraftMock() returns error? { + Draft updatedDraft = check gmailClientForMockServer->/users/me/drafts/["123"].put({ + id: "123", + message: { + to: [recipient], + subject: "Gmail draft test updated" + } + }); + test:assertTrue(updatedDraft.id != "", msg = "/users/[userId]/drafts/[draftId] failed"); +} + +@test:Config { + groups: ["mock"] +} +function testDeleteDraftMock() returns error? { + error? result = gmailClientForMockServer->/users/me/drafts/["!23"].delete(); + test:assertTrue(result is (), msg = "/users/me/drafts/[draftId].delete failed"); +} + +@test:Config { + groups: ["mock"] +} +function testListMailThreadsMock() returns error? { + ListThreadsResponse message = check gmailClientForMockServer->/users/me/threads(); + test:assertTrue(message.nextPageToken != "", msg = "/users/[userId]/messages/send failed"); +} + +@test:Config { + groups: ["mock"] +} +function testGetMailThreadMock() returns error? { + MailThread mailThread = check gmailClientForMockServer->/users/me/threads/["123"]; + test:assertTrue(mailThread.id != "", msg = "/users/[userId]/threads/[threadId] failed"); +} + +@test:Config { + groups: ["mock"] +} +function testModifyMailThreadMock() returns error? { + MailThread mailThread = check gmailClientForMockServer->/users/me/threads/["123"]/modify.post({ + addLabelIds: ["UNREAD"] + }); + test:assertTrue(mailThread.historyId != (), msg = "/users/[userId]/threads/[threadId]/modify failed"); +} + +@test:Config { + groups: ["mock"] +} +function testTrashMailThreadMock() returns error? { + MailThread mailThread = check gmailClientForMockServer->/users/me/threads/["123"]/trash.post(); + test:assertTrue(mailThread.historyId != (), msg = "/users/[userId]/threads/[threadId]/trash failed"); +} + +@test:Config { + groups: ["mock"] +} +function testUntrashMailThreadMock() returns error? { + MailThread mailThread = check gmailClientForMockServer->/users/me/threads/["123"]/untrash.post(); + test:assertTrue(mailThread.historyId != (), msg = "/users/[userId]/threads/[threadId]/untrash failed"); +} + +@test:Config { + groups: ["mock"] +} +function testDeleteMailThreadMock() returns error? { + error? result = gmailClientForMockServer->/users/me/threads/["123"].delete(); + test:assertTrue(result is (), msg = "/users/[userId]/threads/[threadId].delete failed"); +} + +@test:Config { + groups: ["mock"] +} +function testCreateNewLabelMock() returns error? { + Label label = check gmailClientForMockServer->/users/me/labels.post({ + name: "Test Label" + }); + test:assertTrue(label.id != "", msg = "/users/[userId]/labels failed"); +} + +@test:Config { + groups: ["mock"] +} +function testListAllLabelsMock() returns error? { + ListLabelsResponse labelListPage = check gmailClientForMockServer->/users/me/labels(); + test:assertTrue(labelListPage.labels is Label[], msg = "/users/[userId]/labels failed"); +} + +@test:Config { + groups: ["mock"] +} +function testGetLabelMock() returns error? { + Label label = check gmailClientForMockServer->/users/me/labels/["123"]; + test:assertTrue(label.id != "", msg = "/users/[userId]/labels/[label.id] failed"); +} + +@test:Config { + groups: ["mock"] +} +function testUpdateLabelMock() returns error? { + Label label = check gmailClientForMockServer->/users/me/labels/["123"].put({ + id: labelId, + name: "Test Label Updated" + }); + test:assertTrue(label.id != "", msg = "/users/[userId]/labels/[label.id] failed"); +} + +@test:Config { + groups: ["mock"] +} +function testPatchLabelMock() returns error? { + Label label = check gmailClientForMockServer->/users/me/labels/["123"].patch({ + id: labelId, + name: "Test Label Patched" + }); + test:assertTrue(label.id != "", msg = "/users/[userId]/labels/[label.id] failed"); +} + +@test:Config { + groups: ["mock"] +} +function testDeleteLabelMock() returns error? { + check gmailClientForMockServer->/users/me/labels/["123"].delete(); +} + +@test:Config { + groups: ["mock"] +} +function testListHistoryMock() returns error? { + ListHistoryResponse historyListPage = check gmailClientForMockServer->/users/me/history(startHistoryId = "123"); + test:assertTrue(historyListPage.history is History[], msg = "/users/[userId]/history failed"); +} From 1f7c500ea4f895f1efe3b595cef24f407000b763 Mon Sep 17 00:00:00 2001 From: Niveathika Date: Tue, 12 Dec 2023 15:44:36 +0530 Subject: [PATCH 10/10] [Automated] Update the toml files --- ballerina/Ballerina.toml | 2 +- ballerina/Dependencies.toml | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml index 1a1017ed..91c162b6 100644 --- a/ballerina/Ballerina.toml +++ b/ballerina/Ballerina.toml @@ -2,7 +2,7 @@ distribution = "2201.8.0" org = "ballerinax" name = "googleapis.gmail" -version = "4.0.0" +version = "4.0.1" authors = ["Ballerina"] export = ["googleapis.gmail"] repository = "https://github.com/ballerina-platform/module-ballerinax-googleapis.gmail" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 674c7396..d5a5204b 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -61,7 +61,7 @@ dependencies = [ [[package]] org = "ballerina" name = "http" -version = "2.10.4" +version = "2.10.5" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -220,6 +220,9 @@ dependencies = [ {org = "ballerina", name = "lang.value"}, {org = "ballerina", name = "observe"} ] +modules = [ + {org = "ballerina", packageName = "log", moduleName = "log"} +] [[package]] org = "ballerina" @@ -334,12 +337,13 @@ modules = [ [[package]] org = "ballerinax" name = "googleapis.gmail" -version = "4.0.0" +version = "4.0.1" dependencies = [ {org = "ballerina", name = "http"}, {org = "ballerina", name = "io"}, {org = "ballerina", name = "lang.array"}, {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "log"}, {org = "ballerina", name = "os"}, {org = "ballerina", name = "test"}, {org = "ballerina", name = "url"}, @@ -348,6 +352,7 @@ dependencies = [ ] modules = [ {org = "ballerinax", packageName = "googleapis.gmail", moduleName = "googleapis.gmail"}, + {org = "ballerinax", packageName = "googleapis.gmail", moduleName = "googleapis.gmail.mock"}, {org = "ballerinax", packageName = "googleapis.gmail", moduleName = "googleapis.gmail.oas"} ]