diff --git a/package.json b/package.json index ccacebd6e..5c2a98526 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,8 @@ "@google-cloud/precise-date": "^2.0.0", "@google-cloud/projectify": "^2.0.0", "@google-cloud/promisify": "^2.0.0", - "@opentelemetry/api": "^0.12.0", - "@opentelemetry/tracing": "^0.12.0", + "@opentelemetry/api": "^0.18.1", + "@opentelemetry/semantic-conventions": "^0.18.2", "@types/duplexify": "^3.6.0", "@types/long": "^4.0.0", "arrify": "^2.0.0", @@ -69,6 +69,7 @@ "@grpc/proto-loader": "^0.6.0", "@microsoft/api-documenter": "^7.8.10", "@microsoft/api-extractor": "^7.8.10", + "@opentelemetry/tracing": "^0.18.0", "@types/execa": "^0.9.0", "@types/extend": "^3.0.0", "@types/lodash.snakecase": "^4.1.6", @@ -77,7 +78,7 @@ "@types/ncp": "^2.0.1", "@types/node": "^12.12.30", "@types/proxyquire": "^1.3.28", - "@types/sinon": "^9.0.0", + "@types/sinon": "^9.0.11", "@types/tmp": "^0.2.0", "@types/uuid": "^8.0.0", "c8": "^7.0.0", diff --git a/protos/protos.d.ts b/protos/protos.d.ts index 6ae2e2767..2bc15192a 100644 --- a/protos/protos.d.ts +++ b/protos/protos.d.ts @@ -6210,6 +6210,9 @@ export namespace google { /** Http rules */ rules?: (google.api.IHttpRule[]|null); + + /** Http fullyDecodeReservedExpansion */ + fullyDecodeReservedExpansion?: (boolean|null); } /** Represents a Http. */ @@ -6224,6 +6227,9 @@ export namespace google { /** Http rules. */ public rules: google.api.IHttpRule[]; + /** Http fullyDecodeReservedExpansion. */ + public fullyDecodeReservedExpansion: boolean; + /** * Creates a new Http instance using the specified properties. * @param [properties] Properties to set @@ -6322,6 +6328,9 @@ export namespace google { /** HttpRule body */ body?: (string|null); + /** HttpRule responseBody */ + responseBody?: (string|null); + /** HttpRule additionalBindings */ additionalBindings?: (google.api.IHttpRule[]|null); } @@ -6359,6 +6368,9 @@ export namespace google { /** HttpRule body. */ public body: string; + /** HttpRule responseBody. */ + public responseBody: string; + /** HttpRule additionalBindings. */ public additionalBindings: google.api.IHttpRule[]; @@ -7185,6 +7197,9 @@ export namespace google { /** ExtensionRange end */ end?: (number|null); + + /** ExtensionRange options */ + options?: (google.protobuf.IExtensionRangeOptions|null); } /** Represents an ExtensionRange. */ @@ -7202,6 +7217,9 @@ export namespace google { /** ExtensionRange end. */ public end: number; + /** ExtensionRange options. */ + public options?: (google.protobuf.IExtensionRangeOptions|null); + /** * Creates a new ExtensionRange instance using the specified properties. * @param [properties] Properties to set @@ -7370,6 +7388,96 @@ export namespace google { } } + /** Properties of an ExtensionRangeOptions. */ + interface IExtensionRangeOptions { + + /** ExtensionRangeOptions uninterpretedOption */ + uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null); + } + + /** Represents an ExtensionRangeOptions. */ + class ExtensionRangeOptions implements IExtensionRangeOptions { + + /** + * Constructs a new ExtensionRangeOptions. + * @param [properties] Properties to set + */ + constructor(properties?: google.protobuf.IExtensionRangeOptions); + + /** ExtensionRangeOptions uninterpretedOption. */ + public uninterpretedOption: google.protobuf.IUninterpretedOption[]; + + /** + * Creates a new ExtensionRangeOptions instance using the specified properties. + * @param [properties] Properties to set + * @returns ExtensionRangeOptions instance + */ + public static create(properties?: google.protobuf.IExtensionRangeOptions): google.protobuf.ExtensionRangeOptions; + + /** + * Encodes the specified ExtensionRangeOptions message. Does not implicitly {@link google.protobuf.ExtensionRangeOptions.verify|verify} messages. + * @param message ExtensionRangeOptions message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: google.protobuf.IExtensionRangeOptions, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified ExtensionRangeOptions message, length delimited. Does not implicitly {@link google.protobuf.ExtensionRangeOptions.verify|verify} messages. + * @param message ExtensionRangeOptions message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: google.protobuf.IExtensionRangeOptions, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an ExtensionRangeOptions message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns ExtensionRangeOptions + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.ExtensionRangeOptions; + + /** + * Decodes an ExtensionRangeOptions message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns ExtensionRangeOptions + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.ExtensionRangeOptions; + + /** + * Verifies an ExtensionRangeOptions message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates an ExtensionRangeOptions message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns ExtensionRangeOptions + */ + public static fromObject(object: { [k: string]: any }): google.protobuf.ExtensionRangeOptions; + + /** + * Creates a plain object from an ExtensionRangeOptions message. Also converts values to other types if specified. + * @param message ExtensionRangeOptions + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: google.protobuf.ExtensionRangeOptions, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this ExtensionRangeOptions to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + } + /** Properties of a FieldDescriptorProto. */ interface IFieldDescriptorProto { @@ -7402,6 +7510,9 @@ export namespace google { /** FieldDescriptorProto options */ options?: (google.protobuf.IFieldOptions|null); + + /** FieldDescriptorProto proto3Optional */ + proto3Optional?: (boolean|null); } /** Represents a FieldDescriptorProto. */ @@ -7443,6 +7554,9 @@ export namespace google { /** FieldDescriptorProto options. */ public options?: (google.protobuf.IFieldOptions|null); + /** FieldDescriptorProto proto3Optional. */ + public proto3Optional: boolean; + /** * Creates a new FieldDescriptorProto instance using the specified properties. * @param [properties] Properties to set @@ -7653,6 +7767,12 @@ export namespace google { /** EnumDescriptorProto options */ options?: (google.protobuf.IEnumOptions|null); + + /** EnumDescriptorProto reservedRange */ + reservedRange?: (google.protobuf.EnumDescriptorProto.IEnumReservedRange[]|null); + + /** EnumDescriptorProto reservedName */ + reservedName?: (string[]|null); } /** Represents an EnumDescriptorProto. */ @@ -7673,6 +7793,12 @@ export namespace google { /** EnumDescriptorProto options. */ public options?: (google.protobuf.IEnumOptions|null); + /** EnumDescriptorProto reservedRange. */ + public reservedRange: google.protobuf.EnumDescriptorProto.IEnumReservedRange[]; + + /** EnumDescriptorProto reservedName. */ + public reservedName: string[]; + /** * Creates a new EnumDescriptorProto instance using the specified properties. * @param [properties] Properties to set @@ -7744,6 +7870,105 @@ export namespace google { public toJSON(): { [k: string]: any }; } + namespace EnumDescriptorProto { + + /** Properties of an EnumReservedRange. */ + interface IEnumReservedRange { + + /** EnumReservedRange start */ + start?: (number|null); + + /** EnumReservedRange end */ + end?: (number|null); + } + + /** Represents an EnumReservedRange. */ + class EnumReservedRange implements IEnumReservedRange { + + /** + * Constructs a new EnumReservedRange. + * @param [properties] Properties to set + */ + constructor(properties?: google.protobuf.EnumDescriptorProto.IEnumReservedRange); + + /** EnumReservedRange start. */ + public start: number; + + /** EnumReservedRange end. */ + public end: number; + + /** + * Creates a new EnumReservedRange instance using the specified properties. + * @param [properties] Properties to set + * @returns EnumReservedRange instance + */ + public static create(properties?: google.protobuf.EnumDescriptorProto.IEnumReservedRange): google.protobuf.EnumDescriptorProto.EnumReservedRange; + + /** + * Encodes the specified EnumReservedRange message. Does not implicitly {@link google.protobuf.EnumDescriptorProto.EnumReservedRange.verify|verify} messages. + * @param message EnumReservedRange message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: google.protobuf.EnumDescriptorProto.IEnumReservedRange, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified EnumReservedRange message, length delimited. Does not implicitly {@link google.protobuf.EnumDescriptorProto.EnumReservedRange.verify|verify} messages. + * @param message EnumReservedRange message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: google.protobuf.EnumDescriptorProto.IEnumReservedRange, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an EnumReservedRange message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns EnumReservedRange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.protobuf.EnumDescriptorProto.EnumReservedRange; + + /** + * Decodes an EnumReservedRange message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns EnumReservedRange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.protobuf.EnumDescriptorProto.EnumReservedRange; + + /** + * Verifies an EnumReservedRange message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates an EnumReservedRange message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns EnumReservedRange + */ + public static fromObject(object: { [k: string]: any }): google.protobuf.EnumDescriptorProto.EnumReservedRange; + + /** + * Creates a plain object from an EnumReservedRange message. Also converts values to other types if specified. + * @param message EnumReservedRange + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: google.protobuf.EnumDescriptorProto.EnumReservedRange, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this EnumReservedRange to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + } + } + /** Properties of an EnumValueDescriptorProto. */ interface IEnumValueDescriptorProto { @@ -8101,6 +8326,9 @@ export namespace google { /** FileOptions pyGenericServices */ pyGenericServices?: (boolean|null); + /** FileOptions phpGenericServices */ + phpGenericServices?: (boolean|null); + /** FileOptions deprecated */ deprecated?: (boolean|null); @@ -8119,6 +8347,15 @@ export namespace google { /** FileOptions phpClassPrefix */ phpClassPrefix?: (string|null); + /** FileOptions phpNamespace */ + phpNamespace?: (string|null); + + /** FileOptions phpMetadataNamespace */ + phpMetadataNamespace?: (string|null); + + /** FileOptions rubyPackage */ + rubyPackage?: (string|null); + /** FileOptions uninterpretedOption */ uninterpretedOption?: (google.protobuf.IUninterpretedOption[]|null); @@ -8165,6 +8402,9 @@ export namespace google { /** FileOptions pyGenericServices. */ public pyGenericServices: boolean; + /** FileOptions phpGenericServices. */ + public phpGenericServices: boolean; + /** FileOptions deprecated. */ public deprecated: boolean; @@ -8183,6 +8423,15 @@ export namespace google { /** FileOptions phpClassPrefix. */ public phpClassPrefix: string; + /** FileOptions phpNamespace. */ + public phpNamespace: string; + + /** FileOptions phpMetadataNamespace. */ + public phpMetadataNamespace: string; + + /** FileOptions rubyPackage. */ + public rubyPackage: string; + /** FileOptions uninterpretedOption. */ public uninterpretedOption: google.protobuf.IUninterpretedOption[]; diff --git a/protos/protos.js b/protos/protos.js index 456396fe5..2d3c27e71 100644 --- a/protos/protos.js +++ b/protos/protos.js @@ -14123,6 +14123,7 @@ * @memberof google.api * @interface IHttp * @property {Array.|null} [rules] Http rules + * @property {boolean|null} [fullyDecodeReservedExpansion] Http fullyDecodeReservedExpansion */ /** @@ -14149,6 +14150,14 @@ */ Http.prototype.rules = $util.emptyArray; + /** + * Http fullyDecodeReservedExpansion. + * @member {boolean} fullyDecodeReservedExpansion + * @memberof google.api.Http + * @instance + */ + Http.prototype.fullyDecodeReservedExpansion = false; + /** * Creates a new Http instance using the specified properties. * @function create @@ -14176,6 +14185,8 @@ if (message.rules != null && message.rules.length) for (var i = 0; i < message.rules.length; ++i) $root.google.api.HttpRule.encode(message.rules[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.fullyDecodeReservedExpansion != null && Object.hasOwnProperty.call(message, "fullyDecodeReservedExpansion")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.fullyDecodeReservedExpansion); return writer; }; @@ -14215,6 +14226,9 @@ message.rules = []; message.rules.push($root.google.api.HttpRule.decode(reader, reader.uint32())); break; + case 2: + message.fullyDecodeReservedExpansion = reader.bool(); + break; default: reader.skipType(tag & 7); break; @@ -14259,6 +14273,9 @@ return "rules." + error; } } + if (message.fullyDecodeReservedExpansion != null && message.hasOwnProperty("fullyDecodeReservedExpansion")) + if (typeof message.fullyDecodeReservedExpansion !== "boolean") + return "fullyDecodeReservedExpansion: boolean expected"; return null; }; @@ -14284,6 +14301,8 @@ message.rules[i] = $root.google.api.HttpRule.fromObject(object.rules[i]); } } + if (object.fullyDecodeReservedExpansion != null) + message.fullyDecodeReservedExpansion = Boolean(object.fullyDecodeReservedExpansion); return message; }; @@ -14302,11 +14321,15 @@ var object = {}; if (options.arrays || options.defaults) object.rules = []; + if (options.defaults) + object.fullyDecodeReservedExpansion = false; if (message.rules && message.rules.length) { object.rules = []; for (var j = 0; j < message.rules.length; ++j) object.rules[j] = $root.google.api.HttpRule.toObject(message.rules[j], options); } + if (message.fullyDecodeReservedExpansion != null && message.hasOwnProperty("fullyDecodeReservedExpansion")) + object.fullyDecodeReservedExpansion = message.fullyDecodeReservedExpansion; return object; }; @@ -14338,6 +14361,7 @@ * @property {string|null} [patch] HttpRule patch * @property {google.api.ICustomHttpPattern|null} [custom] HttpRule custom * @property {string|null} [body] HttpRule body + * @property {string|null} [responseBody] HttpRule responseBody * @property {Array.|null} [additionalBindings] HttpRule additionalBindings */ @@ -14421,6 +14445,14 @@ */ HttpRule.prototype.body = ""; + /** + * HttpRule responseBody. + * @member {string} responseBody + * @memberof google.api.HttpRule + * @instance + */ + HttpRule.prototype.responseBody = ""; + /** * HttpRule additionalBindings. * @member {Array.} additionalBindings @@ -14486,6 +14518,8 @@ if (message.additionalBindings != null && message.additionalBindings.length) for (var i = 0; i < message.additionalBindings.length; ++i) $root.google.api.HttpRule.encode(message.additionalBindings[i], writer.uint32(/* id 11, wireType 2 =*/90).fork()).ldelim(); + if (message.responseBody != null && Object.hasOwnProperty.call(message, "responseBody")) + writer.uint32(/* id 12, wireType 2 =*/98).string(message.responseBody); return writer; }; @@ -14544,6 +14578,9 @@ case 7: message.body = reader.string(); break; + case 12: + message.responseBody = reader.string(); + break; case 11: if (!(message.additionalBindings && message.additionalBindings.length)) message.additionalBindings = []; @@ -14634,6 +14671,9 @@ if (message.body != null && message.hasOwnProperty("body")) if (!$util.isString(message.body)) return "body: string expected"; + if (message.responseBody != null && message.hasOwnProperty("responseBody")) + if (!$util.isString(message.responseBody)) + return "responseBody: string expected"; if (message.additionalBindings != null && message.hasOwnProperty("additionalBindings")) { if (!Array.isArray(message.additionalBindings)) return "additionalBindings: array expected"; @@ -14677,6 +14717,8 @@ } if (object.body != null) message.body = String(object.body); + if (object.responseBody != null) + message.responseBody = String(object.responseBody); if (object.additionalBindings) { if (!Array.isArray(object.additionalBindings)) throw TypeError(".google.api.HttpRule.additionalBindings: array expected"); @@ -14708,6 +14750,7 @@ if (options.defaults) { object.selector = ""; object.body = ""; + object.responseBody = ""; } if (message.selector != null && message.hasOwnProperty("selector")) object.selector = message.selector; @@ -14748,6 +14791,8 @@ for (var j = 0; j < message.additionalBindings.length; ++j) object.additionalBindings[j] = $root.google.api.HttpRule.toObject(message.additionalBindings[j], options); } + if (message.responseBody != null && message.hasOwnProperty("responseBody")) + object.responseBody = message.responseBody; return object; }; @@ -16999,6 +17044,7 @@ * @interface IExtensionRange * @property {number|null} [start] ExtensionRange start * @property {number|null} [end] ExtensionRange end + * @property {google.protobuf.IExtensionRangeOptions|null} [options] ExtensionRange options */ /** @@ -17032,6 +17078,14 @@ */ ExtensionRange.prototype.end = 0; + /** + * ExtensionRange options. + * @member {google.protobuf.IExtensionRangeOptions|null|undefined} options + * @memberof google.protobuf.DescriptorProto.ExtensionRange + * @instance + */ + ExtensionRange.prototype.options = null; + /** * Creates a new ExtensionRange instance using the specified properties. * @function create @@ -17060,6 +17114,8 @@ writer.uint32(/* id 1, wireType 0 =*/8).int32(message.start); if (message.end != null && Object.hasOwnProperty.call(message, "end")) writer.uint32(/* id 2, wireType 0 =*/16).int32(message.end); + if (message.options != null && Object.hasOwnProperty.call(message, "options")) + $root.google.protobuf.ExtensionRangeOptions.encode(message.options, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); return writer; }; @@ -17100,6 +17156,9 @@ case 2: message.end = reader.int32(); break; + case 3: + message.options = $root.google.protobuf.ExtensionRangeOptions.decode(reader, reader.uint32()); + break; default: reader.skipType(tag & 7); break; @@ -17141,6 +17200,11 @@ if (message.end != null && message.hasOwnProperty("end")) if (!$util.isInteger(message.end)) return "end: integer expected"; + if (message.options != null && message.hasOwnProperty("options")) { + var error = $root.google.protobuf.ExtensionRangeOptions.verify(message.options); + if (error) + return "options." + error; + } return null; }; @@ -17160,6 +17224,11 @@ message.start = object.start | 0; if (object.end != null) message.end = object.end | 0; + if (object.options != null) { + if (typeof object.options !== "object") + throw TypeError(".google.protobuf.DescriptorProto.ExtensionRange.options: object expected"); + message.options = $root.google.protobuf.ExtensionRangeOptions.fromObject(object.options); + } return message; }; @@ -17179,11 +17248,14 @@ if (options.defaults) { object.start = 0; object.end = 0; + object.options = null; } if (message.start != null && message.hasOwnProperty("start")) object.start = message.start; if (message.end != null && message.hasOwnProperty("end")) object.end = message.end; + if (message.options != null && message.hasOwnProperty("options")) + object.options = $root.google.protobuf.ExtensionRangeOptions.toObject(message.options, options); return object; }; @@ -17414,6 +17486,214 @@ return DescriptorProto; })(); + protobuf.ExtensionRangeOptions = (function() { + + /** + * Properties of an ExtensionRangeOptions. + * @memberof google.protobuf + * @interface IExtensionRangeOptions + * @property {Array.|null} [uninterpretedOption] ExtensionRangeOptions uninterpretedOption + */ + + /** + * Constructs a new ExtensionRangeOptions. + * @memberof google.protobuf + * @classdesc Represents an ExtensionRangeOptions. + * @implements IExtensionRangeOptions + * @constructor + * @param {google.protobuf.IExtensionRangeOptions=} [properties] Properties to set + */ + function ExtensionRangeOptions(properties) { + this.uninterpretedOption = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * ExtensionRangeOptions uninterpretedOption. + * @member {Array.} uninterpretedOption + * @memberof google.protobuf.ExtensionRangeOptions + * @instance + */ + ExtensionRangeOptions.prototype.uninterpretedOption = $util.emptyArray; + + /** + * Creates a new ExtensionRangeOptions instance using the specified properties. + * @function create + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {google.protobuf.IExtensionRangeOptions=} [properties] Properties to set + * @returns {google.protobuf.ExtensionRangeOptions} ExtensionRangeOptions instance + */ + ExtensionRangeOptions.create = function create(properties) { + return new ExtensionRangeOptions(properties); + }; + + /** + * Encodes the specified ExtensionRangeOptions message. Does not implicitly {@link google.protobuf.ExtensionRangeOptions.verify|verify} messages. + * @function encode + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {google.protobuf.IExtensionRangeOptions} message ExtensionRangeOptions message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ExtensionRangeOptions.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.uninterpretedOption != null && message.uninterpretedOption.length) + for (var i = 0; i < message.uninterpretedOption.length; ++i) + $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified ExtensionRangeOptions message, length delimited. Does not implicitly {@link google.protobuf.ExtensionRangeOptions.verify|verify} messages. + * @function encodeDelimited + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {google.protobuf.IExtensionRangeOptions} message ExtensionRangeOptions message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ExtensionRangeOptions.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an ExtensionRangeOptions message from the specified reader or buffer. + * @function decode + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {google.protobuf.ExtensionRangeOptions} ExtensionRangeOptions + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ExtensionRangeOptions.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.ExtensionRangeOptions(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 999: + if (!(message.uninterpretedOption && message.uninterpretedOption.length)) + message.uninterpretedOption = []; + message.uninterpretedOption.push($root.google.protobuf.UninterpretedOption.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an ExtensionRangeOptions message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {google.protobuf.ExtensionRangeOptions} ExtensionRangeOptions + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ExtensionRangeOptions.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an ExtensionRangeOptions message. + * @function verify + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + ExtensionRangeOptions.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) { + if (!Array.isArray(message.uninterpretedOption)) + return "uninterpretedOption: array expected"; + for (var i = 0; i < message.uninterpretedOption.length; ++i) { + var error = $root.google.protobuf.UninterpretedOption.verify(message.uninterpretedOption[i]); + if (error) + return "uninterpretedOption." + error; + } + } + return null; + }; + + /** + * Creates an ExtensionRangeOptions message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {Object.} object Plain object + * @returns {google.protobuf.ExtensionRangeOptions} ExtensionRangeOptions + */ + ExtensionRangeOptions.fromObject = function fromObject(object) { + if (object instanceof $root.google.protobuf.ExtensionRangeOptions) + return object; + var message = new $root.google.protobuf.ExtensionRangeOptions(); + if (object.uninterpretedOption) { + if (!Array.isArray(object.uninterpretedOption)) + throw TypeError(".google.protobuf.ExtensionRangeOptions.uninterpretedOption: array expected"); + message.uninterpretedOption = []; + for (var i = 0; i < object.uninterpretedOption.length; ++i) { + if (typeof object.uninterpretedOption[i] !== "object") + throw TypeError(".google.protobuf.ExtensionRangeOptions.uninterpretedOption: object expected"); + message.uninterpretedOption[i] = $root.google.protobuf.UninterpretedOption.fromObject(object.uninterpretedOption[i]); + } + } + return message; + }; + + /** + * Creates a plain object from an ExtensionRangeOptions message. Also converts values to other types if specified. + * @function toObject + * @memberof google.protobuf.ExtensionRangeOptions + * @static + * @param {google.protobuf.ExtensionRangeOptions} message ExtensionRangeOptions + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + ExtensionRangeOptions.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.uninterpretedOption = []; + if (message.uninterpretedOption && message.uninterpretedOption.length) { + object.uninterpretedOption = []; + for (var j = 0; j < message.uninterpretedOption.length; ++j) + object.uninterpretedOption[j] = $root.google.protobuf.UninterpretedOption.toObject(message.uninterpretedOption[j], options); + } + return object; + }; + + /** + * Converts this ExtensionRangeOptions to JSON. + * @function toJSON + * @memberof google.protobuf.ExtensionRangeOptions + * @instance + * @returns {Object.} JSON object + */ + ExtensionRangeOptions.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return ExtensionRangeOptions; + })(); + protobuf.FieldDescriptorProto = (function() { /** @@ -17430,6 +17710,7 @@ * @property {number|null} [oneofIndex] FieldDescriptorProto oneofIndex * @property {string|null} [jsonName] FieldDescriptorProto jsonName * @property {google.protobuf.IFieldOptions|null} [options] FieldDescriptorProto options + * @property {boolean|null} [proto3Optional] FieldDescriptorProto proto3Optional */ /** @@ -17527,6 +17808,14 @@ */ FieldDescriptorProto.prototype.options = null; + /** + * FieldDescriptorProto proto3Optional. + * @member {boolean} proto3Optional + * @memberof google.protobuf.FieldDescriptorProto + * @instance + */ + FieldDescriptorProto.prototype.proto3Optional = false; + /** * Creates a new FieldDescriptorProto instance using the specified properties. * @function create @@ -17571,6 +17860,8 @@ writer.uint32(/* id 9, wireType 0 =*/72).int32(message.oneofIndex); if (message.jsonName != null && Object.hasOwnProperty.call(message, "jsonName")) writer.uint32(/* id 10, wireType 2 =*/82).string(message.jsonName); + if (message.proto3Optional != null && Object.hasOwnProperty.call(message, "proto3Optional")) + writer.uint32(/* id 17, wireType 0 =*/136).bool(message.proto3Optional); return writer; }; @@ -17635,6 +17926,9 @@ case 8: message.options = $root.google.protobuf.FieldOptions.decode(reader, reader.uint32()); break; + case 17: + message.proto3Optional = reader.bool(); + break; default: reader.skipType(tag & 7); break; @@ -17729,6 +18023,9 @@ if (error) return "options." + error; } + if (message.proto3Optional != null && message.hasOwnProperty("proto3Optional")) + if (typeof message.proto3Optional !== "boolean") + return "proto3Optional: boolean expected"; return null; }; @@ -17851,6 +18148,8 @@ throw TypeError(".google.protobuf.FieldDescriptorProto.options: object expected"); message.options = $root.google.protobuf.FieldOptions.fromObject(object.options); } + if (object.proto3Optional != null) + message.proto3Optional = Boolean(object.proto3Optional); return message; }; @@ -17878,6 +18177,7 @@ object.options = null; object.oneofIndex = 0; object.jsonName = ""; + object.proto3Optional = false; } if (message.name != null && message.hasOwnProperty("name")) object.name = message.name; @@ -17899,6 +18199,8 @@ object.oneofIndex = message.oneofIndex; if (message.jsonName != null && message.hasOwnProperty("jsonName")) object.jsonName = message.jsonName; + if (message.proto3Optional != null && message.hasOwnProperty("proto3Optional")) + object.proto3Optional = message.proto3Optional; return object; }; @@ -18202,6 +18504,8 @@ * @property {string|null} [name] EnumDescriptorProto name * @property {Array.|null} [value] EnumDescriptorProto value * @property {google.protobuf.IEnumOptions|null} [options] EnumDescriptorProto options + * @property {Array.|null} [reservedRange] EnumDescriptorProto reservedRange + * @property {Array.|null} [reservedName] EnumDescriptorProto reservedName */ /** @@ -18214,6 +18518,8 @@ */ function EnumDescriptorProto(properties) { this.value = []; + this.reservedRange = []; + this.reservedName = []; if (properties) for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) if (properties[keys[i]] != null) @@ -18244,6 +18550,22 @@ */ EnumDescriptorProto.prototype.options = null; + /** + * EnumDescriptorProto reservedRange. + * @member {Array.} reservedRange + * @memberof google.protobuf.EnumDescriptorProto + * @instance + */ + EnumDescriptorProto.prototype.reservedRange = $util.emptyArray; + + /** + * EnumDescriptorProto reservedName. + * @member {Array.} reservedName + * @memberof google.protobuf.EnumDescriptorProto + * @instance + */ + EnumDescriptorProto.prototype.reservedName = $util.emptyArray; + /** * Creates a new EnumDescriptorProto instance using the specified properties. * @function create @@ -18275,6 +18597,12 @@ $root.google.protobuf.EnumValueDescriptorProto.encode(message.value[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); if (message.options != null && Object.hasOwnProperty.call(message, "options")) $root.google.protobuf.EnumOptions.encode(message.options, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + if (message.reservedRange != null && message.reservedRange.length) + for (var i = 0; i < message.reservedRange.length; ++i) + $root.google.protobuf.EnumDescriptorProto.EnumReservedRange.encode(message.reservedRange[i], writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim(); + if (message.reservedName != null && message.reservedName.length) + for (var i = 0; i < message.reservedName.length; ++i) + writer.uint32(/* id 5, wireType 2 =*/42).string(message.reservedName[i]); return writer; }; @@ -18320,6 +18648,16 @@ case 3: message.options = $root.google.protobuf.EnumOptions.decode(reader, reader.uint32()); break; + case 4: + if (!(message.reservedRange && message.reservedRange.length)) + message.reservedRange = []; + message.reservedRange.push($root.google.protobuf.EnumDescriptorProto.EnumReservedRange.decode(reader, reader.uint32())); + break; + case 5: + if (!(message.reservedName && message.reservedName.length)) + message.reservedName = []; + message.reservedName.push(reader.string()); + break; default: reader.skipType(tag & 7); break; @@ -18372,6 +18710,22 @@ if (error) return "options." + error; } + if (message.reservedRange != null && message.hasOwnProperty("reservedRange")) { + if (!Array.isArray(message.reservedRange)) + return "reservedRange: array expected"; + for (var i = 0; i < message.reservedRange.length; ++i) { + var error = $root.google.protobuf.EnumDescriptorProto.EnumReservedRange.verify(message.reservedRange[i]); + if (error) + return "reservedRange." + error; + } + } + if (message.reservedName != null && message.hasOwnProperty("reservedName")) { + if (!Array.isArray(message.reservedName)) + return "reservedName: array expected"; + for (var i = 0; i < message.reservedName.length; ++i) + if (!$util.isString(message.reservedName[i])) + return "reservedName: string[] expected"; + } return null; }; @@ -18404,6 +18758,23 @@ throw TypeError(".google.protobuf.EnumDescriptorProto.options: object expected"); message.options = $root.google.protobuf.EnumOptions.fromObject(object.options); } + if (object.reservedRange) { + if (!Array.isArray(object.reservedRange)) + throw TypeError(".google.protobuf.EnumDescriptorProto.reservedRange: array expected"); + message.reservedRange = []; + for (var i = 0; i < object.reservedRange.length; ++i) { + if (typeof object.reservedRange[i] !== "object") + throw TypeError(".google.protobuf.EnumDescriptorProto.reservedRange: object expected"); + message.reservedRange[i] = $root.google.protobuf.EnumDescriptorProto.EnumReservedRange.fromObject(object.reservedRange[i]); + } + } + if (object.reservedName) { + if (!Array.isArray(object.reservedName)) + throw TypeError(".google.protobuf.EnumDescriptorProto.reservedName: array expected"); + message.reservedName = []; + for (var i = 0; i < object.reservedName.length; ++i) + message.reservedName[i] = String(object.reservedName[i]); + } return message; }; @@ -18420,8 +18791,11 @@ if (!options) options = {}; var object = {}; - if (options.arrays || options.defaults) + if (options.arrays || options.defaults) { object.value = []; + object.reservedRange = []; + object.reservedName = []; + } if (options.defaults) { object.name = ""; object.options = null; @@ -18435,6 +18809,16 @@ } if (message.options != null && message.hasOwnProperty("options")) object.options = $root.google.protobuf.EnumOptions.toObject(message.options, options); + if (message.reservedRange && message.reservedRange.length) { + object.reservedRange = []; + for (var j = 0; j < message.reservedRange.length; ++j) + object.reservedRange[j] = $root.google.protobuf.EnumDescriptorProto.EnumReservedRange.toObject(message.reservedRange[j], options); + } + if (message.reservedName && message.reservedName.length) { + object.reservedName = []; + for (var j = 0; j < message.reservedName.length; ++j) + object.reservedName[j] = message.reservedName[j]; + } return object; }; @@ -18449,6 +18833,216 @@ return this.constructor.toObject(this, $protobuf.util.toJSONOptions); }; + EnumDescriptorProto.EnumReservedRange = (function() { + + /** + * Properties of an EnumReservedRange. + * @memberof google.protobuf.EnumDescriptorProto + * @interface IEnumReservedRange + * @property {number|null} [start] EnumReservedRange start + * @property {number|null} [end] EnumReservedRange end + */ + + /** + * Constructs a new EnumReservedRange. + * @memberof google.protobuf.EnumDescriptorProto + * @classdesc Represents an EnumReservedRange. + * @implements IEnumReservedRange + * @constructor + * @param {google.protobuf.EnumDescriptorProto.IEnumReservedRange=} [properties] Properties to set + */ + function EnumReservedRange(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * EnumReservedRange start. + * @member {number} start + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @instance + */ + EnumReservedRange.prototype.start = 0; + + /** + * EnumReservedRange end. + * @member {number} end + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @instance + */ + EnumReservedRange.prototype.end = 0; + + /** + * Creates a new EnumReservedRange instance using the specified properties. + * @function create + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {google.protobuf.EnumDescriptorProto.IEnumReservedRange=} [properties] Properties to set + * @returns {google.protobuf.EnumDescriptorProto.EnumReservedRange} EnumReservedRange instance + */ + EnumReservedRange.create = function create(properties) { + return new EnumReservedRange(properties); + }; + + /** + * Encodes the specified EnumReservedRange message. Does not implicitly {@link google.protobuf.EnumDescriptorProto.EnumReservedRange.verify|verify} messages. + * @function encode + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {google.protobuf.EnumDescriptorProto.IEnumReservedRange} message EnumReservedRange message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EnumReservedRange.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.start != null && Object.hasOwnProperty.call(message, "start")) + writer.uint32(/* id 1, wireType 0 =*/8).int32(message.start); + if (message.end != null && Object.hasOwnProperty.call(message, "end")) + writer.uint32(/* id 2, wireType 0 =*/16).int32(message.end); + return writer; + }; + + /** + * Encodes the specified EnumReservedRange message, length delimited. Does not implicitly {@link google.protobuf.EnumDescriptorProto.EnumReservedRange.verify|verify} messages. + * @function encodeDelimited + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {google.protobuf.EnumDescriptorProto.IEnumReservedRange} message EnumReservedRange message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EnumReservedRange.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an EnumReservedRange message from the specified reader or buffer. + * @function decode + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {google.protobuf.EnumDescriptorProto.EnumReservedRange} EnumReservedRange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EnumReservedRange.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.protobuf.EnumDescriptorProto.EnumReservedRange(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.start = reader.int32(); + break; + case 2: + message.end = reader.int32(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an EnumReservedRange message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {google.protobuf.EnumDescriptorProto.EnumReservedRange} EnumReservedRange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EnumReservedRange.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an EnumReservedRange message. + * @function verify + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + EnumReservedRange.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.start != null && message.hasOwnProperty("start")) + if (!$util.isInteger(message.start)) + return "start: integer expected"; + if (message.end != null && message.hasOwnProperty("end")) + if (!$util.isInteger(message.end)) + return "end: integer expected"; + return null; + }; + + /** + * Creates an EnumReservedRange message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {Object.} object Plain object + * @returns {google.protobuf.EnumDescriptorProto.EnumReservedRange} EnumReservedRange + */ + EnumReservedRange.fromObject = function fromObject(object) { + if (object instanceof $root.google.protobuf.EnumDescriptorProto.EnumReservedRange) + return object; + var message = new $root.google.protobuf.EnumDescriptorProto.EnumReservedRange(); + if (object.start != null) + message.start = object.start | 0; + if (object.end != null) + message.end = object.end | 0; + return message; + }; + + /** + * Creates a plain object from an EnumReservedRange message. Also converts values to other types if specified. + * @function toObject + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @static + * @param {google.protobuf.EnumDescriptorProto.EnumReservedRange} message EnumReservedRange + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + EnumReservedRange.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.start = 0; + object.end = 0; + } + if (message.start != null && message.hasOwnProperty("start")) + object.start = message.start; + if (message.end != null && message.hasOwnProperty("end")) + object.end = message.end; + return object; + }; + + /** + * Converts this EnumReservedRange to JSON. + * @function toJSON + * @memberof google.protobuf.EnumDescriptorProto.EnumReservedRange + * @instance + * @returns {Object.} JSON object + */ + EnumReservedRange.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return EnumReservedRange; + })(); + return EnumDescriptorProto; })(); @@ -19267,12 +19861,16 @@ * @property {boolean|null} [ccGenericServices] FileOptions ccGenericServices * @property {boolean|null} [javaGenericServices] FileOptions javaGenericServices * @property {boolean|null} [pyGenericServices] FileOptions pyGenericServices + * @property {boolean|null} [phpGenericServices] FileOptions phpGenericServices * @property {boolean|null} [deprecated] FileOptions deprecated * @property {boolean|null} [ccEnableArenas] FileOptions ccEnableArenas * @property {string|null} [objcClassPrefix] FileOptions objcClassPrefix * @property {string|null} [csharpNamespace] FileOptions csharpNamespace * @property {string|null} [swiftPrefix] FileOptions swiftPrefix * @property {string|null} [phpClassPrefix] FileOptions phpClassPrefix + * @property {string|null} [phpNamespace] FileOptions phpNamespace + * @property {string|null} [phpMetadataNamespace] FileOptions phpMetadataNamespace + * @property {string|null} [rubyPackage] FileOptions rubyPackage * @property {Array.|null} [uninterpretedOption] FileOptions uninterpretedOption * @property {Array.|null} [".google.api.resourceDefinition"] FileOptions .google.api.resourceDefinition */ @@ -19374,6 +19972,14 @@ */ FileOptions.prototype.pyGenericServices = false; + /** + * FileOptions phpGenericServices. + * @member {boolean} phpGenericServices + * @memberof google.protobuf.FileOptions + * @instance + */ + FileOptions.prototype.phpGenericServices = false; + /** * FileOptions deprecated. * @member {boolean} deprecated @@ -19388,7 +19994,7 @@ * @memberof google.protobuf.FileOptions * @instance */ - FileOptions.prototype.ccEnableArenas = false; + FileOptions.prototype.ccEnableArenas = true; /** * FileOptions objcClassPrefix. @@ -19422,6 +20028,30 @@ */ FileOptions.prototype.phpClassPrefix = ""; + /** + * FileOptions phpNamespace. + * @member {string} phpNamespace + * @memberof google.protobuf.FileOptions + * @instance + */ + FileOptions.prototype.phpNamespace = ""; + + /** + * FileOptions phpMetadataNamespace. + * @member {string} phpMetadataNamespace + * @memberof google.protobuf.FileOptions + * @instance + */ + FileOptions.prototype.phpMetadataNamespace = ""; + + /** + * FileOptions rubyPackage. + * @member {string} rubyPackage + * @memberof google.protobuf.FileOptions + * @instance + */ + FileOptions.prototype.rubyPackage = ""; + /** * FileOptions uninterpretedOption. * @member {Array.} uninterpretedOption @@ -19494,6 +20124,14 @@ writer.uint32(/* id 39, wireType 2 =*/314).string(message.swiftPrefix); if (message.phpClassPrefix != null && Object.hasOwnProperty.call(message, "phpClassPrefix")) writer.uint32(/* id 40, wireType 2 =*/322).string(message.phpClassPrefix); + if (message.phpNamespace != null && Object.hasOwnProperty.call(message, "phpNamespace")) + writer.uint32(/* id 41, wireType 2 =*/330).string(message.phpNamespace); + if (message.phpGenericServices != null && Object.hasOwnProperty.call(message, "phpGenericServices")) + writer.uint32(/* id 42, wireType 0 =*/336).bool(message.phpGenericServices); + if (message.phpMetadataNamespace != null && Object.hasOwnProperty.call(message, "phpMetadataNamespace")) + writer.uint32(/* id 44, wireType 2 =*/354).string(message.phpMetadataNamespace); + if (message.rubyPackage != null && Object.hasOwnProperty.call(message, "rubyPackage")) + writer.uint32(/* id 45, wireType 2 =*/362).string(message.rubyPackage); if (message.uninterpretedOption != null && message.uninterpretedOption.length) for (var i = 0; i < message.uninterpretedOption.length; ++i) $root.google.protobuf.UninterpretedOption.encode(message.uninterpretedOption[i], writer.uint32(/* id 999, wireType 2 =*/7994).fork()).ldelim(); @@ -19564,6 +20202,9 @@ case 18: message.pyGenericServices = reader.bool(); break; + case 42: + message.phpGenericServices = reader.bool(); + break; case 23: message.deprecated = reader.bool(); break; @@ -19582,6 +20223,15 @@ case 40: message.phpClassPrefix = reader.string(); break; + case 41: + message.phpNamespace = reader.string(); + break; + case 44: + message.phpMetadataNamespace = reader.string(); + break; + case 45: + message.rubyPackage = reader.string(); + break; case 999: if (!(message.uninterpretedOption && message.uninterpretedOption.length)) message.uninterpretedOption = []; @@ -19663,6 +20313,9 @@ if (message.pyGenericServices != null && message.hasOwnProperty("pyGenericServices")) if (typeof message.pyGenericServices !== "boolean") return "pyGenericServices: boolean expected"; + if (message.phpGenericServices != null && message.hasOwnProperty("phpGenericServices")) + if (typeof message.phpGenericServices !== "boolean") + return "phpGenericServices: boolean expected"; if (message.deprecated != null && message.hasOwnProperty("deprecated")) if (typeof message.deprecated !== "boolean") return "deprecated: boolean expected"; @@ -19681,6 +20334,15 @@ if (message.phpClassPrefix != null && message.hasOwnProperty("phpClassPrefix")) if (!$util.isString(message.phpClassPrefix)) return "phpClassPrefix: string expected"; + if (message.phpNamespace != null && message.hasOwnProperty("phpNamespace")) + if (!$util.isString(message.phpNamespace)) + return "phpNamespace: string expected"; + if (message.phpMetadataNamespace != null && message.hasOwnProperty("phpMetadataNamespace")) + if (!$util.isString(message.phpMetadataNamespace)) + return "phpMetadataNamespace: string expected"; + if (message.rubyPackage != null && message.hasOwnProperty("rubyPackage")) + if (!$util.isString(message.rubyPackage)) + return "rubyPackage: string expected"; if (message.uninterpretedOption != null && message.hasOwnProperty("uninterpretedOption")) { if (!Array.isArray(message.uninterpretedOption)) return "uninterpretedOption: array expected"; @@ -19746,6 +20408,8 @@ message.javaGenericServices = Boolean(object.javaGenericServices); if (object.pyGenericServices != null) message.pyGenericServices = Boolean(object.pyGenericServices); + if (object.phpGenericServices != null) + message.phpGenericServices = Boolean(object.phpGenericServices); if (object.deprecated != null) message.deprecated = Boolean(object.deprecated); if (object.ccEnableArenas != null) @@ -19758,6 +20422,12 @@ message.swiftPrefix = String(object.swiftPrefix); if (object.phpClassPrefix != null) message.phpClassPrefix = String(object.phpClassPrefix); + if (object.phpNamespace != null) + message.phpNamespace = String(object.phpNamespace); + if (object.phpMetadataNamespace != null) + message.phpMetadataNamespace = String(object.phpMetadataNamespace); + if (object.rubyPackage != null) + message.rubyPackage = String(object.rubyPackage); if (object.uninterpretedOption) { if (!Array.isArray(object.uninterpretedOption)) throw TypeError(".google.protobuf.FileOptions.uninterpretedOption: array expected"); @@ -19810,11 +20480,15 @@ object.javaGenerateEqualsAndHash = false; object.deprecated = false; object.javaStringCheckUtf8 = false; - object.ccEnableArenas = false; + object.ccEnableArenas = true; object.objcClassPrefix = ""; object.csharpNamespace = ""; object.swiftPrefix = ""; object.phpClassPrefix = ""; + object.phpNamespace = ""; + object.phpGenericServices = false; + object.phpMetadataNamespace = ""; + object.rubyPackage = ""; } if (message.javaPackage != null && message.hasOwnProperty("javaPackage")) object.javaPackage = message.javaPackage; @@ -19848,6 +20522,14 @@ object.swiftPrefix = message.swiftPrefix; if (message.phpClassPrefix != null && message.hasOwnProperty("phpClassPrefix")) object.phpClassPrefix = message.phpClassPrefix; + if (message.phpNamespace != null && message.hasOwnProperty("phpNamespace")) + object.phpNamespace = message.phpNamespace; + if (message.phpGenericServices != null && message.hasOwnProperty("phpGenericServices")) + object.phpGenericServices = message.phpGenericServices; + if (message.phpMetadataNamespace != null && message.hasOwnProperty("phpMetadataNamespace")) + object.phpMetadataNamespace = message.phpMetadataNamespace; + if (message.rubyPackage != null && message.hasOwnProperty("rubyPackage")) + object.rubyPackage = message.rubyPackage; if (message.uninterpretedOption && message.uninterpretedOption.length) { object.uninterpretedOption = []; for (var j = 0; j < message.uninterpretedOption.length; ++j) diff --git a/protos/protos.json b/protos/protos.json index ac1aae86d..f81292a93 100644 --- a/protos/protos.json +++ b/protos/protos.json @@ -1637,6 +1637,10 @@ "rule": "repeated", "type": "HttpRule", "id": 1 + }, + "fullyDecodeReservedExpansion": { + "type": "bool", + "id": 2 } } }, @@ -1686,6 +1690,10 @@ "type": "string", "id": 7 }, + "responseBody": { + "type": "string", + "id": 12 + }, "additionalBindings": { "rule": "repeated", "type": "HttpRule", @@ -1819,11 +1827,12 @@ }, "protobuf": { "options": { - "go_package": "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor", + "go_package": "google.golang.org/protobuf/types/descriptorpb", "java_package": "com.google.protobuf", "java_outer_classname": "DescriptorProtos", "csharp_namespace": "Google.Protobuf.Reflection", "objc_class_prefix": "GPB", + "cc_enable_arenas": true, "optimize_for": "SPEED" }, "nested": { @@ -1962,6 +1971,10 @@ "end": { "type": "int32", "id": 2 + }, + "options": { + "type": "ExtensionRangeOptions", + "id": 3 } } }, @@ -1979,6 +1992,21 @@ } } }, + "ExtensionRangeOptions": { + "fields": { + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, "FieldDescriptorProto": { "fields": { "name": { @@ -2020,6 +2048,10 @@ "options": { "type": "FieldOptions", "id": 8 + }, + "proto3Optional": { + "type": "bool", + "id": 17 } }, "nested": { @@ -2080,6 +2112,30 @@ "options": { "type": "EnumOptions", "id": 3 + }, + "reservedRange": { + "rule": "repeated", + "type": "EnumReservedRange", + "id": 4 + }, + "reservedName": { + "rule": "repeated", + "type": "string", + "id": 5 + } + }, + "nested": { + "EnumReservedRange": { + "fields": { + "start": { + "type": "int32", + "id": 1 + }, + "end": { + "type": "int32", + "id": 2 + } + } } } }, @@ -2213,6 +2269,13 @@ "default": false } }, + "phpGenericServices": { + "type": "bool", + "id": 42, + "options": { + "default": false + } + }, "deprecated": { "type": "bool", "id": 23, @@ -2224,7 +2287,7 @@ "type": "bool", "id": 31, "options": { - "default": false + "default": true } }, "objcClassPrefix": { @@ -2243,6 +2306,18 @@ "type": "string", "id": 40 }, + "phpNamespace": { + "type": "string", + "id": 41 + }, + "phpMetadataNamespace": { + "type": "string", + "id": 44 + }, + "rubyPackage": { + "type": "string", + "id": 45 + }, "uninterpretedOption": { "rule": "repeated", "type": "UninterpretedOption", diff --git a/samples/openTelemetryTracing.js b/samples/openTelemetryTracing.js index 6c0190110..5d6c29569 100644 --- a/samples/openTelemetryTracing.js +++ b/samples/openTelemetryTracing.js @@ -62,9 +62,13 @@ function main( const provider = new BasicTracerProvider(); const exporter = new ConsoleSpanExporter(); provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); + // Enable the diagnostic logger for Opentelemetry + opentelemetry.diag.setLogger( + new opentelemetry.DiagConsoleLogger(), + opentelemetry.DiagLogLevel.INFO + ); provider.register(); - opentelemetry.trace.setGlobalTracerProvider(provider); // OpenTelemetry tracing is an optional feature and can be enabled by setting // enableOpenTelemetryTraceing as a publisher or subscriber option @@ -89,17 +93,32 @@ function main( const messageHandler = message => { console.log(`Message ${message.id} received.`); message.ack(); - process.exit(0); + + // Ensure that all spans got flushed by the exporter + console.log('Cleaning up Opentelemetry exporter...'); + exporter.shutdown().then(() => { + // Cleaned up exporter. + process.exit(0); + }); }; const errorHandler = error => { console.log('Received error:', error); - process.exit(0); + + console.log('Cleaning up Opentelemetry exporter...'); + exporter.shutdown().then(() => { + // Cleaned up exporter. + process.exit(0); + }); }; // Listens for new messages from the topic - pubSubClient.subscription(subscriptionName).on('message', messageHandler); - pubSubClient.subscription(subscriptionName).on('error', errorHandler); + pubSubClient + .subscription(subscriptionName, enableOpenTelemetryTracing) + .on('message', messageHandler); + pubSubClient + .subscription(subscriptionName, enableOpenTelemetryTracing) + .on('error', errorHandler); setTimeout(() => { pubSubClient diff --git a/samples/package.json b/samples/package.json index b008e7c01..4f7ea1ee8 100644 --- a/samples/package.json +++ b/samples/package.json @@ -15,8 +15,8 @@ }, "dependencies": { "@google-cloud/pubsub": "^2.10.0", - "@opentelemetry/api": "^0.11.0", - "@opentelemetry/tracing": "^0.11.0" + "@opentelemetry/api": "^0.18.1", + "@opentelemetry/tracing": "^0.18.2" }, "devDependencies": { "chai": "^4.2.0", diff --git a/samples/system-test/openTelemetryTracing.test.js b/samples/system-test/openTelemetryTracing.test.js index bcc069084..c91f174e2 100644 --- a/samples/system-test/openTelemetryTracing.test.js +++ b/samples/system-test/openTelemetryTracing.test.js @@ -42,7 +42,6 @@ describe('openTelemetry', () => { const stdout = execSync( `node openTelemetryTracing ${topicName} ${subName}` ); - assert.match(stdout, /traceId/); assert.match(stdout, /Message .* published./); assert.match(stdout, /Message .* received/); assert.notMatch(stdout, /Received error/); diff --git a/src/opentelemetry-tracing.ts b/src/opentelemetry-tracing.ts index 3c51dd440..42261a91a 100644 --- a/src/opentelemetry-tracing.ts +++ b/src/opentelemetry-tracing.ts @@ -13,31 +13,50 @@ * limitations under the License. */ -import {Attributes, SpanContext, Span, trace} from '@opentelemetry/api'; -import {Tracer} from '@opentelemetry/tracing'; +import { + Tracer, + SpanAttributes, + SpanContext, + Span, + context, + trace, + setSpanContext, + SpanKind, +} from '@opentelemetry/api'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const PKG = require('../../package.json'); + +/** + * @internal + * Instantiates a Opentelemetry tracer for the library + */ +const libraryTracer: Tracer = trace.getTracer( + '@google-cloud/pubsub', + PKG.version +); /** - * Wrapper for creating OpenTelemetry Spans + * Creates a new span with the given properties * - * @class + * @param {string} spanName the name for the span + * @param {Attributes?} attributes an object containing the attributes to be set for the span + * @param {SpanContext?} parent the context of the parent span to link to the span */ -export class OpenTelemetryTracer { - /** - * Creates a new span with the given properties - * - * @param {string} spanName the name for the span - * @param {Attributes?} attributes an object containing the attributes to be set for the span - * @param {SpanContext?} parent the context of the parent span to link to the span - */ - createSpan( - spanName: string, - attributes?: Attributes, - parent?: SpanContext - ): Span { - const tracerProvider: Tracer = trace.getTracer('default') as Tracer; - return tracerProvider.startSpan(spanName, { - parent: parent, +export function createSpan( + spanName: string, + kind: SpanKind, + attributes?: SpanAttributes, + parent?: SpanContext +): Span { + return libraryTracer.startSpan( + spanName, + { + // set the kind of the span + kind, + // set the attributes of the span attributes: attributes, - }); - } + }, + parent ? setSpanContext(context.active(), parent) : undefined + ); } diff --git a/src/publisher/index.ts b/src/publisher/index.ts index 483990f96..bcd8d9e33 100644 --- a/src/publisher/index.ts +++ b/src/publisher/index.ts @@ -17,7 +17,8 @@ import {promisify, promisifyAll} from '@google-cloud/promisify'; import * as extend from 'extend'; import {CallOptions} from 'google-gax'; -import {Span} from '@opentelemetry/api'; +import {MessagingAttribute} from '@opentelemetry/semantic-conventions'; +import {isSpanContextValid, Span, SpanKind} from '@opentelemetry/api'; import {BatchPublishOptions} from './message-batch'; import {Queue, OrderedQueue} from './message-queues'; @@ -25,7 +26,7 @@ import {Topic} from '../topic'; import {RequestCallback, EmptyCallback} from '../pubsub'; import {google} from '../../protos/protos'; import {defaultOptions} from '../default-options'; -import {OpenTelemetryTracer} from '../opentelemetry-tracing'; +import {createSpan} from '../opentelemetry-tracing'; export type PubsubMessage = google.pubsub.v1.IPubsubMessage; @@ -75,16 +76,11 @@ export class Publisher { settings!: PublishOptions; queue: Queue; orderedQueues: Map; - tracing: OpenTelemetryTracer | undefined; constructor(topic: Topic, options?: PublishOptions) { this.setOptions(options); this.topic = topic; this.queue = new Queue(this); this.orderedQueues = new Map(); - this.tracing = - this.settings && this.settings.enableOpenTelemetryTracing - ? new OpenTelemetryTracer() - : undefined; } flush(): Promise; @@ -238,10 +234,6 @@ export class Publisher { enableOpenTelemetryTracing, } = extend(true, defaults, options); - this.tracing = enableOpenTelemetryTracing - ? new OpenTelemetryTracer() - : undefined; - this.settings = { batching: { maxBytes: Math.min(batching.maxBytes, BATCH_LIMITS.maxBytes!), @@ -262,13 +254,33 @@ export class Publisher { * @param {PubsubMessage} message The message to create a span for */ constructSpan(message: PubsubMessage): Span | undefined { + if (!this.settings.enableOpenTelemetryTracing) { + return undefined; + } + const spanAttributes = { - data: message.data, + // Add Opentelemetry semantic convention attributes to the span, based on: + // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.1.0/specification/trace/semantic_conventions/messaging.md + [MessagingAttribute.MESSAGING_TEMP_DESTINATION]: false, + [MessagingAttribute.MESSAGING_SYSTEM]: 'pubsub', + [MessagingAttribute.MESSAGING_OPERATION]: 'send', + [MessagingAttribute.MESSAGING_DESTINATION]: this.topic.name, + [MessagingAttribute.MESSAGING_DESTINATION_KIND]: 'topic', + [MessagingAttribute.MESSAGING_MESSAGE_ID]: message.messageId, + [MessagingAttribute.MESSAGING_PROTOCOL]: 'pubsub', + [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: + message.data?.length, + 'messaging.pubsub.ordering_key': message.orderingKey, } as Attributes; - const span: Span | undefined = this.tracing - ? this.tracing.createSpan(`${this.topic.name} publisher`, spanAttributes) - : undefined; - if (span) { + + const span: Span = createSpan( + `${this.topic.name} send`, + SpanKind.PRODUCER, + spanAttributes + ); + + // If the span's context is valid we should pass the span context special attribute + if (isSpanContextValid(span.context())) { if ( message.attributes && message.attributes['googclient_OpenTelemetrySpanContext'] @@ -280,10 +292,12 @@ export class Publisher { if (!message.attributes) { message.attributes = {}; } + message.attributes[ 'googclient_OpenTelemetrySpanContext' ] = JSON.stringify(span.context()); } + return span; } } diff --git a/src/subscriber.ts b/src/subscriber.ts index 97b863094..bff1bb98d 100644 --- a/src/subscriber.ts +++ b/src/subscriber.ts @@ -18,7 +18,8 @@ import {DateStruct, PreciseDate} from '@google-cloud/precise-date'; import {replaceProjectIdToken} from '@google-cloud/projectify'; import {promisify} from '@google-cloud/promisify'; import {EventEmitter} from 'events'; -import {SpanContext, Span} from '@opentelemetry/api'; +import {SpanContext, Span, SpanKind} from '@opentelemetry/api'; +import {MessagingAttribute} from '@opentelemetry/semantic-conventions'; import {google} from '../protos/protos'; import {Histogram} from './histogram'; @@ -28,7 +29,7 @@ import {MessageStream, MessageStreamOptions} from './message-stream'; import {Subscription} from './subscription'; import {defaultOptions} from './default-options'; import {SubscriberClient} from './v1'; -import {OpenTelemetryTracer} from './opentelemetry-tracing'; +import {createSpan} from './opentelemetry-tracing'; export type PullResponse = google.pubsub.v1.IPullResponse; @@ -239,13 +240,13 @@ export class Subscriber extends EventEmitter { private _histogram: Histogram; private _inventory!: LeaseManager; private _isUserSetDeadline: boolean; + private _useOpentelemetry: boolean; private _latencies: Histogram; private _modAcks!: ModAckQueue; private _name!: string; private _options!: SubscriberOptions; private _stream!: MessageStream; private _subscription: Subscription; - private _tracing: OpenTelemetryTracer | undefined; constructor(subscription: Subscription, options = {}) { super(); @@ -255,6 +256,7 @@ export class Subscriber extends EventEmitter { this.useLegacyFlowControl = false; this.isOpen = false; this._isUserSetDeadline = false; + this._useOpentelemetry = false; this._histogram = new Histogram({min: 10, max: 600}); this._latencies = new Histogram(); this._subscription = subscription; @@ -403,6 +405,8 @@ export class Subscriber extends EventEmitter { setOptions(options: SubscriberOptions): void { this._options = options; + this._useOpentelemetry = options.enableOpenTelemetryTracing || false; + if (options.ackDeadline) { this.ackDeadline = options.ackDeadline; this._isUserSetDeadline = true; @@ -433,9 +437,6 @@ export class Subscriber extends EventEmitter { this.maxMessages ); } - this._tracing = options.enableOpenTelemetryTracing - ? new OpenTelemetryTracer() - : undefined; } /** @@ -447,24 +448,47 @@ export class Subscriber extends EventEmitter { private _constructSpan(message: Message): Span | undefined { // Handle cases where OpenTelemetry is disabled or no span context was sent through message if ( - !this._tracing || + !this._useOpentelemetry || !message.attributes || !message.attributes['googclient_OpenTelemetrySpanContext'] ) { return undefined; } + const spanValue = message.attributes['googclient_OpenTelemetrySpanContext']; const parentSpanContext: SpanContext | undefined = spanValue ? JSON.parse(spanValue) : undefined; const spanAttributes = { + // Original span attributes ackId: message.ackId, deliveryAttempt: message.deliveryAttempt, + // + // based on https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md#topic-with-multiple-consumers + [MessagingAttribute.MESSAGING_SYSTEM]: 'pubsub', + [MessagingAttribute.MESSAGING_OPERATION]: 'process', + [MessagingAttribute.MESSAGING_DESTINATION]: this.name, + [MessagingAttribute.MESSAGING_DESTINATION_KIND]: 'topic', + [MessagingAttribute.MESSAGING_MESSAGE_ID]: message.id, + [MessagingAttribute.MESSAGING_PROTOCOL]: 'pubsub', + [MessagingAttribute.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES]: (message.data as Buffer) + .length, + // Not in Opentelemetry semantic convention but mimics naming + 'messaging.pubsub.received_at': message.received, + 'messaging.pubsub.acknowlege_id': message.ackId, + 'messaging.pubsub.delivery_attempt': message.deliveryAttempt, }; + // Subscriber spans should always have a publisher span as a parent. // Return undefined if no parent is provided + const spanName = `${this.name} process`; const span = parentSpanContext - ? this._tracing.createSpan(this._name, spanAttributes, parentSpanContext) + ? createSpan( + spanName.trim(), + SpanKind.CONSUMER, + spanAttributes, + parentSpanContext + ) : undefined; return span; } @@ -491,6 +515,7 @@ export class Subscriber extends EventEmitter { const message = new Message(this, data); const span: Span | undefined = this._constructSpan(message); + if (this.isOpen) { message.modAck(this.ackDeadline); this._inventory.add(message); diff --git a/test/opentelemetry-tracing.ts b/test/opentelemetry-tracing.ts index 032a23533..dc6a1423e 100644 --- a/test/opentelemetry-tracing.ts +++ b/test/opentelemetry-tracing.ts @@ -15,15 +15,15 @@ */ import * as assert from 'assert'; -import {describe, it, before, beforeEach, afterEach} from 'mocha'; +import {describe, it, beforeEach} from 'mocha'; import * as api from '@opentelemetry/api'; import * as trace from '@opentelemetry/tracing'; -import {OpenTelemetryTracer} from '../src/opentelemetry-tracing'; -import {SimpleSpanProcessor} from '@opentelemetry/tracing'; +import {createSpan} from '../src/opentelemetry-tracing'; +import {exporter} from './tracing'; +import {SpanKind} from '@opentelemetry/api'; describe('OpenTelemetryTracer', () => { - let tracing: OpenTelemetryTracer; let span: trace.Span; const spanName = 'test-span'; const spanContext: api.SpanContext = { @@ -31,33 +31,30 @@ describe('OpenTelemetryTracer', () => { spanId: '6e0c63257de34c92', traceFlags: api.TraceFlags.SAMPLED, }; - const spanAttributes: api.Attributes = { + const spanAttributes: api.SpanAttributes = { foo: 'bar', }; - before(() => { - const provider = new trace.BasicTracerProvider(); - const exporter = new trace.InMemorySpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - api.trace.setGlobalTracerProvider(provider); - }); - beforeEach(() => { - tracing = new OpenTelemetryTracer(); - }); - - afterEach(() => { - span.end(); + exporter.reset(); }); it('creates a span', () => { - span = tracing.createSpan( + span = createSpan( spanName, + SpanKind.PRODUCER, spanAttributes, spanContext ) as trace.Span; - assert.strictEqual(span.name, spanName); - assert.deepStrictEqual(span.attributes, spanAttributes); - assert.strictEqual(span.parentSpanId, spanContext.spanId); + span.end(); + + const spans = exporter.getFinishedSpans(); + assert.notStrictEqual(spans.length, 0); + const exportedSpan = spans.concat().pop()!; + + assert.strictEqual(exportedSpan.name, spanName); + assert.deepStrictEqual(exportedSpan.attributes, spanAttributes); + assert.strictEqual(exportedSpan.parentSpanId, spanContext.spanId); + assert.strictEqual(exportedSpan.kind, SpanKind.PRODUCER); }); }); diff --git a/test/publisher/index.ts b/test/publisher/index.ts index ad59e3604..7440bad66 100644 --- a/test/publisher/index.ts +++ b/test/publisher/index.ts @@ -16,23 +16,20 @@ import * as pfy from '@google-cloud/promisify'; import * as assert from 'assert'; -import {describe, it, before, beforeEach, afterEach} from 'mocha'; +import {describe, it, beforeEach, afterEach} from 'mocha'; import {EventEmitter} from 'events'; import * as proxyquire from 'proxyquire'; import * as sinon from 'sinon'; -import { - BasicTracerProvider, - InMemorySpanExporter, - SimpleSpanProcessor, -} from '@opentelemetry/tracing'; import * as opentelemetry from '@opentelemetry/api'; - import {Topic} from '../../src'; import * as p from '../../src/publisher'; import * as q from '../../src/publisher/message-queues'; import {PublishError} from '../../src/publisher/publish-error'; import {defaultOptions} from '../../src/default-options'; +import {exporter} from '../tracing'; +import {SpanKind} from '@opentelemetry/api'; +import {MessagingAttribute} from '@opentelemetry/semantic-conventions'; let promisified = false; const fakePromisify = Object.assign({}, pfy, { @@ -94,14 +91,21 @@ class FakeOrderedQueue extends FakeQueue { } describe('Publisher', () => { - const sandbox = sinon.createSandbox(); - const topic = {} as Topic; + let sandbox: sinon.SinonSandbox; + let spy: sinon.SinonSpyStatic; + const topic = { + name: 'topic-name', + pubsub: {projectId: 'PROJECT_ID'}, + } as Topic; // tslint:disable-next-line variable-name let Publisher: typeof p.Publisher; let publisher: p.Publisher; - before(() => { + beforeEach(() => { + sandbox = sinon.createSandbox(); + spy = sandbox.spy(); + const mocked = proxyquire('../../src/publisher/index.js', { '@google-cloud/promisify': fakePromisify, './message-queues': { @@ -111,9 +115,7 @@ describe('Publisher', () => { }); Publisher = mocked.Publisher; - }); - beforeEach(() => { publisher = new Publisher(topic); }); @@ -151,7 +153,6 @@ describe('Publisher', () => { describe('publish', () => { const buffer = Buffer.from('Hello, world!'); - const spy = sandbox.spy(); it('should call through to publishMessage', () => { const stub = sandbox.stub(publisher, 'publishMessage'); @@ -180,56 +181,52 @@ describe('Publisher', () => { const enableTracing: p.PublishOptions = { enableOpenTelemetryTracing: true, }; - const disableTracing: p.PublishOptions = { - enableOpenTelemetryTracing: false, - }; const buffer = Buffer.from('Hello, world!'); beforeEach(() => { - // Declare tracingPublisher as type any and pre-define _tracing - // to gain access to the private field after publisher init - tracingPublisher['tracing'] = undefined; - }); - it('should not instantiate a tracer when tracing is disabled', () => { - tracingPublisher = new Publisher(topic); - assert.strictEqual(tracingPublisher['tracing'], undefined); - }); - - it('should instantiate a tracer when tracing is enabled through constructor', () => { - tracingPublisher = new Publisher(topic, enableTracing); - assert.ok(tracingPublisher['tracing']); - }); - - it('should instantiate a tracer when tracing is enabled through setOptions', () => { - tracingPublisher = new Publisher(topic); - tracingPublisher.setOptions(enableTracing); - assert.ok(tracingPublisher['tracing']); - }); - - it('should disable tracing when tracing is disabled through setOptions', () => { - tracingPublisher = new Publisher(topic, enableTracing); - tracingPublisher.setOptions(disableTracing); - assert.strictEqual(tracingPublisher['tracing'], undefined); + exporter.reset(); }); it('export created spans', () => { - tracingPublisher = new Publisher(topic, enableTracing); - // Setup trace exporting - const provider: BasicTracerProvider = new BasicTracerProvider(); - const exporter: InMemorySpanExporter = new InMemorySpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - provider.register(); - opentelemetry.trace.setGlobalTracerProvider(provider); + tracingPublisher = new Publisher(topic, enableTracing); tracingPublisher.publish(buffer); - assert.ok(exporter.getFinishedSpans()); + const spans = exporter.getFinishedSpans(); + assert.notStrictEqual(spans.length, 0, 'has span'); + const createdSpan = spans.concat().pop()!; + assert.strictEqual( + createdSpan.status.code, + opentelemetry.SpanStatusCode.UNSET + ); + assert.strictEqual( + createdSpan.attributes[MessagingAttribute.MESSAGING_OPERATION], + 'send' + ); + assert.strictEqual( + createdSpan.attributes[MessagingAttribute.MESSAGING_SYSTEM], + 'pubsub' + ); + assert.strictEqual( + createdSpan.attributes[MessagingAttribute.MESSAGING_DESTINATION], + topic.name + ); + assert.strictEqual( + createdSpan.attributes[MessagingAttribute.MESSAGING_DESTINATION_KIND], + 'topic' + ); + assert.strictEqual(createdSpan.name, 'topic-name send'); + assert.strictEqual( + createdSpan.kind, + SpanKind.PRODUCER, + 'span kind should be PRODUCER' + ); + assert.ok(spans); }); }); describe('publishMessage', () => { const data = Buffer.from('hello, world!'); - const spy = sandbox.spy(); it('should throw an error if data is not a Buffer', () => { const badData = {} as Buffer; diff --git a/test/subscriber.ts b/test/subscriber.ts index 82064954f..031934e03 100644 --- a/test/subscriber.ts +++ b/test/subscriber.ts @@ -14,19 +14,15 @@ * limitations under the License. */ +import {exporter} from './tracing'; import * as assert from 'assert'; -import {describe, it, before, beforeEach, afterEach} from 'mocha'; +import {describe, it, beforeEach, afterEach} from 'mocha'; import {EventEmitter} from 'events'; import {common as protobuf} from 'protobufjs'; import * as proxyquire from 'proxyquire'; import * as sinon from 'sinon'; import {PassThrough} from 'stream'; import * as uuid from 'uuid'; -import { - SimpleSpanProcessor, - BasicTracerProvider, - InMemorySpanExporter, -} from '@opentelemetry/tracing'; import * as opentelemetry from '@opentelemetry/api'; import {HistogramOptions} from '../src/histogram'; @@ -35,6 +31,8 @@ import {BatchOptions} from '../src/message-queues'; import {MessageStreamOptions} from '../src/message-stream'; import * as s from '../src/subscriber'; import {Subscription} from '../src/subscription'; +import {SpanKind} from '@opentelemetry/api'; +import {MessagingAttribute} from '@opentelemetry/semantic-conventions'; const stubs = new Map(); @@ -150,10 +148,9 @@ const RECEIVED_MESSAGE = { }; describe('Subscriber', () => { - const sandbox = sinon.createSandbox(); - - const fakeProjectify = {replaceProjectIdToken: sandbox.stub()}; + let sandbox: sinon.SinonSandbox; + let fakeProjectify: any; let subscription: Subscription; // tslint:disable-next-line variable-name @@ -163,7 +160,14 @@ describe('Subscriber', () => { let Subscriber: typeof s.Subscriber; let subscriber: s.Subscriber; - before(() => { + beforeEach(() => { + sandbox = sinon.createSandbox(); + fakeProjectify = { + replaceProjectIdToken: sandbox.stub().callsFake((name, projectId) => { + return `projects/${projectId}/name/${name}`; + }), + }; + const s = proxyquire('../src/subscriber.js', { '@google-cloud/precise-date': {PreciseDate: FakePreciseDate}, '@google-cloud/projectify': fakeProjectify, @@ -178,9 +182,8 @@ describe('Subscriber', () => { Message = s.Message; Subscriber = s.Subscriber; - }); - beforeEach(() => { + // Create standard instance subscription = (new FakeSubscription() as {}) as Subscription; subscriber = new Subscriber(subscription); message = new Message(subscriber, RECEIVED_MESSAGE); @@ -638,7 +641,6 @@ describe('Subscriber', () => { }); describe('OpenTelemetry tracing', () => { - let tracingSubscriber: s.Subscriber = {} as s.Subscriber; const enableTracing: s.SubscriberOptions = { enableOpenTelemetryTracing: true, }; @@ -647,41 +649,42 @@ describe('Subscriber', () => { }; beforeEach(() => { - // Pre-define _tracing to gain access to the private field after subscriber init - tracingSubscriber['_tracing'] = undefined; + exporter.reset(); + }); + + afterEach(() => { + exporter.reset(); + subscriber.close(); }); it('should not instantiate a tracer when tracing is disabled', () => { - tracingSubscriber = new Subscriber(subscription); - assert.strictEqual(tracingSubscriber['_tracing'], undefined); + subscriber = new Subscriber(subscription, {}); + assert.strictEqual(subscriber['_useOpentelemetry'], false); }); it('should instantiate a tracer when tracing is enabled through constructor', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); - assert.ok(tracingSubscriber['_tracing']); + subscriber = new Subscriber(subscription, enableTracing); + assert.ok(subscriber['_useOpentelemetry']); }); it('should instantiate a tracer when tracing is enabled through setOptions', () => { - tracingSubscriber = new Subscriber(subscription); - tracingSubscriber.setOptions(enableTracing); - assert.ok(tracingSubscriber['_tracing']); + subscriber = new Subscriber(subscription, {}); + subscriber.setOptions(enableTracing); + assert.ok(subscriber['_useOpentelemetry']); }); it('should disable tracing when tracing is disabled through setOptions', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); - tracingSubscriber.setOptions(disableTracing); - assert.strictEqual(tracingSubscriber['_tracing'], undefined); + subscriber = new Subscriber(subscription, enableTracing); + subscriber.setOptions(disableTracing); + assert.strictEqual(subscriber['_useOpentelemetry'], false); }); it('exports a span once it is created', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); - - // Setup trace exporting - const provider: BasicTracerProvider = new BasicTracerProvider(); - const exporter: InMemorySpanExporter = new InMemorySpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - provider.register(); - opentelemetry.trace.setGlobalTracerProvider(provider); + subscription = (new FakeSubscription() as {}) as Subscription; + subscriber = new Subscriber(subscription, enableTracing); + message = new Message(subscriber, RECEIVED_MESSAGE); + assert.strictEqual(subscriber['_useOpentelemetry'], true); + subscriber.open(); // Construct mock of received message with span context const parentSpanContext: opentelemetry.SpanContext = { @@ -708,20 +711,51 @@ describe('Subscriber', () => { }; // Receive message and assert that it was exported - const stream: FakeMessageStream = stubs.get('messageStream'); - stream.emit('data', pullResponse); - assert.ok(exporter.getFinishedSpans()); + const msgStream = stubs.get('messageStream'); + msgStream.emit('data', pullResponse); + + const spans = exporter.getFinishedSpans(); + assert.strictEqual(spans.length, 1); + const firstSpan = spans.concat().shift(); + assert.ok(firstSpan); + assert.strictEqual(firstSpan.parentSpanId, parentSpanContext.spanId); + assert.strictEqual( + firstSpan.name, + `${subscriber.name} process`, + 'name of span should match' + ); + assert.strictEqual( + firstSpan.kind, + SpanKind.CONSUMER, + 'span kind should be CONSUMER' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_OPERATION], + 'process', + 'span messaging operation should match' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_SYSTEM], + 'pubsub' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_MESSAGE_ID], + messageWithSpanContext.message.messageId, + 'span messaging id should match' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_DESTINATION], + subscriber.name, + 'span messaging destination should match' + ); + assert.strictEqual( + firstSpan.attributes[MessagingAttribute.MESSAGING_DESTINATION_KIND], + 'topic' + ); }); it('does not export a span when a span context is not present on message', () => { - tracingSubscriber = new Subscriber(subscription, enableTracing); - - // Setup trace exporting - const provider: BasicTracerProvider = new BasicTracerProvider(); - const exporter: InMemorySpanExporter = new InMemorySpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - provider.register(); - opentelemetry.trace.setGlobalTracerProvider(provider); + subscriber = new Subscriber(subscription, enableTracing); const pullResponse: s.PullResponse = { receivedMessages: [RECEIVED_MESSAGE], diff --git a/test/tracing.ts b/test/tracing.ts new file mode 100644 index 000000000..8b1b31146 --- /dev/null +++ b/test/tracing.ts @@ -0,0 +1,41 @@ +/*! + * Copyright 2021 Google LLC. All Rights Reserved. + * + * Licensed 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 { + BasicTracerProvider, + InMemorySpanExporter, + SimpleSpanProcessor, +} from '@opentelemetry/tracing'; + +/** + * This file is used to initialise a global tracing provider and span exporter + * for our tests used in our project. This was the only way I was able to get + * the tracing tests to work. + * + * Now before each test related or touches Opentelemetry + * we are resetting the exporter defined below to ensure there are no spans + * from previous tests still in memory. This is achived by calling `reset` + * on the exporter in the unit tests while keeping one instance of + * the trace provider and exporter. + * + * The tracing provider is being registered as a global trace provider before + * we are importing our actual code which uses the Opentelemetry API to ensure + * its defined beforehand. + */ +export const exporter: InMemorySpanExporter = new InMemorySpanExporter(); +export const provider: BasicTracerProvider = new BasicTracerProvider(); +provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); +provider.register();