| // Copyright (c) HashiCorp, Inc. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| package tfjson | |
| import ( | |
| "encoding/json" | |
| "testing" | |
| "time" | |
| "github.com/google/go-cmp/cmp" | |
| "github.com/hashicorp/go-version" | |
| ) | |
| var cmpOpts = cmp.AllowUnexported(allLogMessageTypes...) | |
| func TestLogging_generic(t *testing.T) { | |
| testCases := []struct { | |
| rawMessage string | |
| expectedMessage LogMsg | |
| }{ | |
| { | |
| `{"@level":"info","@message":"Installing provider version: hashicorp/aws v6.8.0...","@module":"terraform.ui","@timestamp":"2025-08-11T15:09:18.827459+00:00","type":"log"}`, | |
| LogMessage{ | |
| baseLogMessage: baseLogMessage{ | |
| Lvl: Info, | |
| Msg: "Installing provider version: hashicorp/aws v6.8.0...", | |
| Time: time.Date(2025, 8, 11, 15, 9, 18, 827459000, time.UTC), | |
| }, | |
| }, | |
| }, | |
| { | |
| `{"@level":"info","@message":"Terraform 1.9.0","@module":"terraform.ui","@timestamp":"2025-08-11T15:09:15.919212+00:00","terraform":"1.9.0","type":"version","ui":"1.2"}`, | |
| VersionLogMessage{ | |
| baseLogMessage: baseLogMessage{ | |
| Lvl: Info, | |
| Msg: "Terraform 1.9.0", | |
| Time: time.Date(2025, 8, 11, 15, 9, 15, 919212000, time.UTC), | |
| }, | |
| Terraform: version.Must(version.NewVersion("1.9.0")), | |
| UI: version.Must(version.NewVersion("1.2")), | |
| }, | |
| }, | |
| { | |
| `{"@level":"error","@message":"Error: Unclosed configuration block","@module":"terraform.ui","@timestamp":"2025-08-13T10:40:46.749685+00:00","diagnostic":{"severity":"error","summary":"Unclosed configuration block","detail":"There is no closing brace for this block before the end of the file. This may be caused by incorrect brace nesting elsewhere in this file.","range":{"filename":"main.tf","start":{"line":11,"column":30,"byte":153},"end":{"line":11,"column":31,"byte":154}},"snippet":{"context":"resource \"random_pet\" \"name\"","code":"resource \"random_pet\" \"name\" {","start_line":11,"highlight_start_offset":29,"highlight_end_offset":30,"values":[]}},"type":"diagnostic"}`, | |
| DiagnosticLogMessage{ | |
| baseLogMessage: baseLogMessage{ | |
| Lvl: Error, | |
| Msg: "Error: Unclosed configuration block", | |
| Time: time.Date(2025, 8, 13, 10, 40, 46, 749685000, time.UTC), | |
| }, | |
| Diagnostic: Diagnostic{ | |
| Severity: DiagnosticSeverityError, | |
| Summary: "Unclosed configuration block", | |
| Detail: "There is no closing brace for this block before the end of the file. This may be caused by incorrect brace nesting elsewhere in this file.", | |
| Range: &Range{ | |
| Filename: "main.tf", | |
| Start: Pos{ | |
| Line: 11, | |
| Column: 30, | |
| Byte: 153, | |
| }, | |
| End: Pos{ | |
| Line: 11, | |
| Column: 31, | |
| Byte: 154, | |
| }, | |
| }, | |
| Snippet: &DiagnosticSnippet{ | |
| Context: ptrToString(`resource "random_pet" "name"`), | |
| Code: `resource "random_pet" "name" {`, | |
| StartLine: 11, | |
| HighlightStartOffset: 29, | |
| HighlightEndOffset: 30, | |
| Values: []DiagnosticExpressionValue{}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| `{"@level":"debug","@message":"Foobar","@module":"terraform.ui","@timestamp":"2025-08-11T15:09:18.827459+00:00","type":"FOO"}`, | |
| UnknownLogMessage{ | |
| baseLogMessage: baseLogMessage{ | |
| Lvl: Debug, | |
| Msg: "Foobar", | |
| Time: time.Date(2025, 8, 11, 15, 9, 18, 827459000, time.UTC), | |
| }, | |
| }, | |
| }, | |
| } | |
| for _, tc := range testCases { | |
| msg, err := UnmarshalLogMessage([]byte(tc.rawMessage)) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| if diff := cmp.Diff(tc.expectedMessage, msg, cmpOpts); diff != "" { | |
| t.Fatalf("unexpected message: %s", diff) | |
| } | |
| } | |
| } | |
| func TestLogging_query(t *testing.T) { | |
| testCases := []struct { | |
| rawMessage string | |
| expectedMessage LogMsg | |
| }{ | |
| { | |
| `{"@level":"info","@message":"list.concept_pet.pets: Starting query...","@module":"terraform.ui","@timestamp":"2025-08-28T18:07:11.534006+00:00","list_start":{"address":"list.concept_pet.pets","resource_type":"concept_pet"},"type":"list_start"}`, | |
| ListStartMessage{ | |
| baseLogMessage: baseLogMessage{ | |
| Lvl: Info, | |
| Msg: "list.concept_pet.pets: Starting query...", | |
| Time: time.Date(2025, 8, 28, 18, 7, 11, 534006000, time.UTC), | |
| }, | |
| ListStart: ListStartData{ | |
| Address: "list.concept_pet.pets", | |
| ResourceType: "concept_pet", | |
| InputConfig: nil, | |
| }, | |
| }, | |
| }, | |
| { | |
| `{"@level":"info","@message":"list.concept_pet.pets: Result found","@module":"terraform.ui","@timestamp":"2025-08-28T18:07:11.534589+00:00","list_resource_found":{"address":"list.concept_pet.pets","display_name":"This is a easy-antelope","identity":{"id":"easy-antelope","legs":6},"resource_type":"concept_pet"},"type":"list_resource_found"}`, | |
| ListResourceFoundMessage{ | |
| baseLogMessage: baseLogMessage{ | |
| Lvl: Info, | |
| Msg: "list.concept_pet.pets: Result found", | |
| Time: time.Date(2025, 8, 28, 18, 7, 11, 534589000, time.UTC), | |
| }, | |
| ListResourceFound: ListResourceFoundData{ | |
| Address: "list.concept_pet.pets", | |
| ResourceType: "concept_pet", | |
| DisplayName: "This is a easy-antelope", | |
| Identity: map[string]json.RawMessage{ | |
| "id": json.RawMessage(`"easy-antelope"`), | |
| "legs": json.RawMessage("6"), | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| `{"@level":"info","@message":"list.concept_pet.pets: List complete","@module":"terraform.ui","@timestamp":"2025-08-28T18:07:11.534661+00:00","list_complete":{"address":"list.concept_pet.pets","resource_type":"concept_pet","total":5},"type":"list_complete"}`, | |
| ListCompleteMessage{ | |
| baseLogMessage: baseLogMessage{ | |
| Lvl: Info, | |
| Msg: "list.concept_pet.pets: List complete", | |
| Time: time.Date(2025, 8, 28, 18, 7, 11, 534661000, time.UTC), | |
| }, | |
| ListComplete: ListCompleteData{ | |
| Address: "list.concept_pet.pets", | |
| ResourceType: "concept_pet", | |
| Total: 5, | |
| }, | |
| }, | |
| }, | |
| } | |
| for _, tc := range testCases { | |
| msg, err := UnmarshalLogMessage([]byte(tc.rawMessage)) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| if diff := cmp.Diff(tc.expectedMessage, msg, cmpOpts); diff != "" { | |
| t.Fatalf("unexpected message: %s", diff) | |
| } | |
| } | |
| } |