You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

334 lines
9.2 KiB

  1. // Copyright 2016 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Tests that require access to unexported names of the logging package.
  15. package logging
  16. import (
  17. "encoding/json"
  18. "net/http"
  19. "net/url"
  20. "testing"
  21. "time"
  22. "cloud.google.com/go/internal/testutil"
  23. "github.com/golang/protobuf/proto"
  24. durpb "github.com/golang/protobuf/ptypes/duration"
  25. structpb "github.com/golang/protobuf/ptypes/struct"
  26. "google.golang.org/api/support/bundler"
  27. mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
  28. logtypepb "google.golang.org/genproto/googleapis/logging/type"
  29. )
  30. func TestLoggerCreation(t *testing.T) {
  31. const logID = "testing"
  32. c := &Client{parent: "projects/PROJECT_ID"}
  33. customResource := &mrpb.MonitoredResource{
  34. Type: "global",
  35. Labels: map[string]string{
  36. "project_id": "ANOTHER_PROJECT",
  37. },
  38. }
  39. defaultBundler := &bundler.Bundler{
  40. DelayThreshold: DefaultDelayThreshold,
  41. BundleCountThreshold: DefaultEntryCountThreshold,
  42. BundleByteThreshold: DefaultEntryByteThreshold,
  43. BundleByteLimit: 0,
  44. BufferedByteLimit: DefaultBufferedByteLimit,
  45. }
  46. for _, test := range []struct {
  47. options []LoggerOption
  48. wantLogger *Logger
  49. defaultResource bool
  50. wantBundler *bundler.Bundler
  51. }{
  52. {
  53. options: nil,
  54. wantLogger: &Logger{},
  55. defaultResource: true,
  56. wantBundler: defaultBundler,
  57. },
  58. {
  59. options: []LoggerOption{
  60. CommonResource(nil),
  61. CommonLabels(map[string]string{"a": "1"}),
  62. },
  63. wantLogger: &Logger{
  64. commonResource: nil,
  65. commonLabels: map[string]string{"a": "1"},
  66. },
  67. wantBundler: defaultBundler,
  68. },
  69. {
  70. options: []LoggerOption{CommonResource(customResource)},
  71. wantLogger: &Logger{commonResource: customResource},
  72. wantBundler: defaultBundler,
  73. },
  74. {
  75. options: []LoggerOption{
  76. DelayThreshold(time.Minute),
  77. EntryCountThreshold(99),
  78. EntryByteThreshold(17),
  79. EntryByteLimit(18),
  80. BufferedByteLimit(19),
  81. },
  82. wantLogger: &Logger{},
  83. defaultResource: true,
  84. wantBundler: &bundler.Bundler{
  85. DelayThreshold: time.Minute,
  86. BundleCountThreshold: 99,
  87. BundleByteThreshold: 17,
  88. BundleByteLimit: 18,
  89. BufferedByteLimit: 19,
  90. },
  91. },
  92. } {
  93. gotLogger := c.Logger(logID, test.options...)
  94. if got, want := gotLogger.commonResource, test.wantLogger.commonResource; !test.defaultResource && !proto.Equal(got, want) {
  95. t.Errorf("%v: resource: got %v, want %v", test.options, got, want)
  96. }
  97. if got, want := gotLogger.commonLabels, test.wantLogger.commonLabels; !testutil.Equal(got, want) {
  98. t.Errorf("%v: commonLabels: got %v, want %v", test.options, got, want)
  99. }
  100. if got, want := gotLogger.bundler.DelayThreshold, test.wantBundler.DelayThreshold; got != want {
  101. t.Errorf("%v: DelayThreshold: got %v, want %v", test.options, got, want)
  102. }
  103. if got, want := gotLogger.bundler.BundleCountThreshold, test.wantBundler.BundleCountThreshold; got != want {
  104. t.Errorf("%v: BundleCountThreshold: got %v, want %v", test.options, got, want)
  105. }
  106. if got, want := gotLogger.bundler.BundleByteThreshold, test.wantBundler.BundleByteThreshold; got != want {
  107. t.Errorf("%v: BundleByteThreshold: got %v, want %v", test.options, got, want)
  108. }
  109. if got, want := gotLogger.bundler.BundleByteLimit, test.wantBundler.BundleByteLimit; got != want {
  110. t.Errorf("%v: BundleByteLimit: got %v, want %v", test.options, got, want)
  111. }
  112. if got, want := gotLogger.bundler.BufferedByteLimit, test.wantBundler.BufferedByteLimit; got != want {
  113. t.Errorf("%v: BufferedByteLimit: got %v, want %v", test.options, got, want)
  114. }
  115. }
  116. }
  117. func TestToProtoStruct(t *testing.T) {
  118. v := struct {
  119. Foo string `json:"foo"`
  120. Bar int `json:"bar,omitempty"`
  121. Baz []float64 `json:"baz"`
  122. Moo map[string]interface{} `json:"moo"`
  123. }{
  124. Foo: "foovalue",
  125. Baz: []float64{1.1},
  126. Moo: map[string]interface{}{
  127. "a": 1,
  128. "b": "two",
  129. "c": true,
  130. },
  131. }
  132. got, err := toProtoStruct(v)
  133. if err != nil {
  134. t.Fatal(err)
  135. }
  136. want := &structpb.Struct{
  137. Fields: map[string]*structpb.Value{
  138. "foo": {Kind: &structpb.Value_StringValue{StringValue: v.Foo}},
  139. "baz": {Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{Values: []*structpb.Value{
  140. {Kind: &structpb.Value_NumberValue{NumberValue: 1.1}},
  141. }}}},
  142. "moo": {Kind: &structpb.Value_StructValue{
  143. StructValue: &structpb.Struct{
  144. Fields: map[string]*structpb.Value{
  145. "a": {Kind: &structpb.Value_NumberValue{NumberValue: 1}},
  146. "b": {Kind: &structpb.Value_StringValue{StringValue: "two"}},
  147. "c": {Kind: &structpb.Value_BoolValue{BoolValue: true}},
  148. },
  149. },
  150. }},
  151. },
  152. }
  153. if !proto.Equal(got, want) {
  154. t.Errorf("got %+v\nwant %+v", got, want)
  155. }
  156. // Non-structs should fail to convert.
  157. for v := range []interface{}{3, "foo", []int{1, 2, 3}} {
  158. _, err := toProtoStruct(v)
  159. if err == nil {
  160. t.Errorf("%v: got nil, want error", v)
  161. }
  162. }
  163. // Test fast path.
  164. got, err = toProtoStruct(want)
  165. if err != nil {
  166. t.Fatal(err)
  167. }
  168. if got != want {
  169. t.Error("got and want should be identical, but are not")
  170. }
  171. }
  172. func TestToLogEntryPayload(t *testing.T) {
  173. for _, test := range []struct {
  174. in interface{}
  175. wantText string
  176. wantStruct *structpb.Struct
  177. }{
  178. {
  179. in: "string",
  180. wantText: "string",
  181. },
  182. {
  183. in: map[string]interface{}{"a": 1, "b": true},
  184. wantStruct: &structpb.Struct{
  185. Fields: map[string]*structpb.Value{
  186. "a": {Kind: &structpb.Value_NumberValue{NumberValue: 1}},
  187. "b": {Kind: &structpb.Value_BoolValue{BoolValue: true}},
  188. },
  189. },
  190. },
  191. {
  192. in: json.RawMessage([]byte(`{"a": 1, "b": true}`)),
  193. wantStruct: &structpb.Struct{
  194. Fields: map[string]*structpb.Value{
  195. "a": {Kind: &structpb.Value_NumberValue{NumberValue: 1}},
  196. "b": {Kind: &structpb.Value_BoolValue{BoolValue: true}},
  197. },
  198. },
  199. },
  200. } {
  201. e, err := toLogEntry(Entry{Payload: test.in})
  202. if err != nil {
  203. t.Fatalf("%+v: %v", test.in, err)
  204. }
  205. if test.wantStruct != nil {
  206. got := e.GetJsonPayload()
  207. if !proto.Equal(got, test.wantStruct) {
  208. t.Errorf("%+v: got %s, want %s", test.in, got, test.wantStruct)
  209. }
  210. } else {
  211. got := e.GetTextPayload()
  212. if got != test.wantText {
  213. t.Errorf("%+v: got %s, want %s", test.in, got, test.wantText)
  214. }
  215. }
  216. }
  217. }
  218. func TestFromHTTPRequest(t *testing.T) {
  219. const testURL = "http:://example.com/path?q=1"
  220. u, err := url.Parse(testURL)
  221. if err != nil {
  222. t.Fatal(err)
  223. }
  224. req := &HTTPRequest{
  225. Request: &http.Request{
  226. Method: "GET",
  227. URL: u,
  228. Header: map[string][]string{
  229. "User-Agent": {"user-agent"},
  230. "Referer": {"referer"},
  231. },
  232. },
  233. RequestSize: 100,
  234. Status: 200,
  235. ResponseSize: 25,
  236. Latency: 100 * time.Second,
  237. LocalIP: "127.0.0.1",
  238. RemoteIP: "10.0.1.1",
  239. CacheHit: true,
  240. CacheValidatedWithOriginServer: true,
  241. }
  242. got := fromHTTPRequest(req)
  243. want := &logtypepb.HttpRequest{
  244. RequestMethod: "GET",
  245. RequestUrl: testURL,
  246. RequestSize: 100,
  247. Status: 200,
  248. ResponseSize: 25,
  249. Latency: &durpb.Duration{Seconds: 100},
  250. UserAgent: "user-agent",
  251. ServerIp: "127.0.0.1",
  252. RemoteIp: "10.0.1.1",
  253. Referer: "referer",
  254. CacheHit: true,
  255. CacheValidatedWithOriginServer: true,
  256. }
  257. if !proto.Equal(got, want) {
  258. t.Errorf("got %+v\nwant %+v", got, want)
  259. }
  260. }
  261. func TestMonitoredResource(t *testing.T) {
  262. for _, test := range []struct {
  263. parent string
  264. want *mrpb.MonitoredResource
  265. }{
  266. {
  267. "projects/P",
  268. &mrpb.MonitoredResource{
  269. Type: "project",
  270. Labels: map[string]string{"project_id": "P"},
  271. },
  272. },
  273. {
  274. "folders/F",
  275. &mrpb.MonitoredResource{
  276. Type: "folder",
  277. Labels: map[string]string{"folder_id": "F"},
  278. },
  279. },
  280. {
  281. "billingAccounts/B",
  282. &mrpb.MonitoredResource{
  283. Type: "billing_account",
  284. Labels: map[string]string{"account_id": "B"},
  285. },
  286. },
  287. {
  288. "organizations/123",
  289. &mrpb.MonitoredResource{
  290. Type: "organization",
  291. Labels: map[string]string{"organization_id": "123"},
  292. },
  293. },
  294. {
  295. "unknown/X",
  296. &mrpb.MonitoredResource{
  297. Type: "global",
  298. Labels: map[string]string{"project_id": "X"},
  299. },
  300. },
  301. {
  302. "whatever",
  303. &mrpb.MonitoredResource{
  304. Type: "global",
  305. Labels: map[string]string{"project_id": "whatever"},
  306. },
  307. },
  308. } {
  309. got := monitoredResource(test.parent)
  310. if !testutil.Equal(got, test.want) {
  311. t.Errorf("%q: got %+v, want %+v", test.parent, got, test.want)
  312. }
  313. }
  314. }
  315. // Used by the tests in logging_test.
  316. func SetNow(f func() time.Time) {
  317. now = f
  318. }