<commit_before>package json

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"strings"

	messages "github.com/cucumber/cucumber-messages-go/v6"
	gio "github.com/gogo/protobuf/io"
)

type jsonFeature struct {
	Description string               `json:"description"`
	Elements    []jsonFeatureElement `json:"elements"`
	ID          string               `json:"id"`
	Keyword     string               `json:"keyword"`
	Line        uint32               `json:"line"`
	Name        string               `json:"name"`
	URI         string               `json:"uri"`
	Tags        []jsonTag            `json:"tags,omitempty"`
}

type jsonFeatureElement struct {
	Description string      `json:"description"`
	ID          string      `json:"id,omitempty"`
	Keyword     string      `json:"keyword"`
	Line        uint32      `json:"line"`
	Name        string      `json:"name"`
	Steps       []*jsonStep `json:"steps"`
	Type        string      `json:"type"`
	Tags        []jsonTag   `json:"tags,omitempty"`
}

type jsonStep struct {
	Keyword   string              `json:"keyword"`
	Line      uint32              `json:"line"`
	Name      string              `json:"name"`
	Result    *jsonStepResult     `json:"result"`
	Match     *jsonStepMatch      `json:"match,omitempty"`
	DocString *jsonDocString      `json:"doc_string,omitempty"`
	Rows      []*jsonDatatableRow `json:"rows,omitempty"`
}

type jsonDocString struct {
	ContentType string `json:"content_type"`
	Line        uint32 `json:"line"`
	Value       string `json:"value"`
}

type jsonDatatableRow struct {
	Cells []string `json:"cells"`
}

type jsonStepResult struct {
	Duration     uint64 `json:"duration,omitempty"`
	Status       string `json:"status"`
	ErrorMessage string `json:"error_message,omitempty"`
}

type jsonStepMatch struct {
	Location string `json:"location"`
}

type jsonTag struct {
	Line uint32 `json:"line"`
	Name string `json:"name"`
}

type Formatter struct {
	backgroundByUri      map[string]*messages.GherkinDocument_Feature_Background
	backgroundStepsByKey map[string]*messages.GherkinDocument_Feature_Step
	exampleByRowKey      map[string]*messages.GherkinDocument_Feature_Scenario_Examples
	exampleRowIndexByKey map[string]int
	gherkinDocumentByURI map[string]*messages.GherkinDocument
	jsonFeatures         []*jsonFeature
	jsonFeaturesByURI    map[string]*jsonFeature
	jsonStepsByKey       map[string]*jsonStep
	pickleById           map[string]*messages.Pickle
	scenariosByKey       map[string]*messages.GherkinDocument_Feature_Scenario
	scenarioStepsByKey   map[string]*messages.GherkinDocument_Feature_Step
}

// ProcessMessages writes a JSON report to STDOUT
func (formatter *Formatter) ProcessMessages(stdin io.Reader, stdout io.Writer) (err error) {
	formatter.jsonFeatures = make([]*jsonFeature, 0)
	formatter.jsonFeaturesByURI = make(map[string]*jsonFeature)
	formatter.jsonStepsByKey = make(map[string]*jsonStep)

	formatter.backgroundByUri = make(map[string]*messages.GherkinDocument_Feature_Background)
	formatter.backgroundStepsByKey = make(map[string]*messages.GherkinDocument_Feature_Step)
	formatter.exampleByRowKey = make(map[string]*messages.GherkinDocument_Feature_Scenario_Examples)
	formatter.exampleRowIndexByKey = make(map[string]int)
	formatter.gherkinDocumentByURI = make(map[string]*messages.GherkinDocument)
	formatter.pickleById = make(map[string]*messages.Pickle)
	formatter.scenariosByKey = make(map[string]*messages.GherkinDocument_Feature_Scenario)
	formatter.scenarioStepsByKey = make(map[string]*messages.GherkinDocument_Feature_Step)

	r := gio.NewDelimitedReader(stdin, 4096)

	for {
		wrapper := &messages.Envelope{}
		err := r.ReadMsg(wrapper)
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		switch m := wrapper.Message.(type) {
		case *messages.Envelope_GherkinDocument:
			formatter.gherkinDocumentByURI[m.GherkinDocument.Uri] = m.GherkinDocument
			for _, child := range m.GherkinDocument.Feature.Children {
				if child.GetBackground() != nil {
					formatter.backgroundByUri[m.GherkinDocument.Uri] = child.GetBackground()
					for _, step := range child.GetBackground().Steps {
						formatter.backgroundStepsByKey[key(m.GherkinDocument.Uri, step.Location)] = step
					}
				}

				if child.GetScenario() != nil {
					formatter.scenariosByKey[key(m.GherkinDocument.Uri, child.GetScenario().Location)] = child.GetScenario()
					for _, step := range child.GetScenario().Steps {
						formatter.scenarioStepsByKey[key(m.GherkinDocument.Uri, step.Location)] = step
					}

					for _, example := range child.GetScenario().Examples {
						for rowIndex, row := range example.TableBody {
							rowKey := key(m.GherkinDocument.Uri, row.Location)
							formatter.exampleByRowKey[rowKey] = example
							// Add 1 for the row header, and another 1 because the id is 1-based
							formatter.exampleRowIndexByKey[rowKey] = rowIndex + 2
						}
					}
				}
			}

		case *messages.Envelope_Pickle:
			pickle := m.Pickle
			formatter.pickleById[pickle.Id] = pickle
			jsonFeature := formatter.findOrCreateJsonFeature(pickle)

			scenario := formatter.scenariosByKey[key(pickle.Uri, pickle.Locations[0])]

			scenarioJsonSteps := make([]*jsonStep, 0)
			backgroundJsonSteps := make([]*jsonStep, 0)

			for _, pickleStep := range pickle.Steps {
				isBackgroundStep := false
				step := formatter.scenarioStepsByKey[key(pickle.Uri, pickleStep.Locations[0])]

				if step == nil {
					step = formatter.backgroundStepsByKey[key(pickle.Uri, pickleStep.Locations[0])]
					isBackgroundStep = true
				}

				jsonStep := &jsonStep{
					Keyword: step.Keyword,
					Line:    step.Location.Line,
					Name:    pickleStep.Text,
					// The match field defaults to the Gherkin step itself for some curious reason
					Match: &jsonStepMatch{
						Location: fmt.Sprintf("%s:%d", pickle.Uri, pickleStep.Locations[len(pickleStep.Locations)-1].Line),
					},
				}
				if isBackgroundStep {
					backgroundJsonSteps = append(backgroundJsonSteps, jsonStep)
				} else {
					scenarioJsonSteps = append(scenarioJsonSteps, jsonStep)
				}

				docString := step.GetDocString()
				if docString != nil {
					jsonStep.DocString = &jsonDocString{
						Line:        docString.Location.Line,
						ContentType: docString.ContentType,
						Value:       docString.Content,
					}
				}

				datatable := step.GetDataTable()
				if datatable != nil {
					jsonStep.Rows = make([]*jsonDatatableRow, len(datatable.GetRows()))
					for rowIndex, row := range datatable.GetRows() {
						cells := make([]string, len(row.Cells))
						for cellIndex, cell := range row.Cells {
							cells[cellIndex] = cell.Value
						}

						jsonStep.Rows[rowIndex] = &jsonDatatableRow{
							Cells: cells,
						}
					}
				}

				formatter.jsonStepsByKey[key(pickle.Uri, step.Location)] = jsonStep
			}

			if len(backgroundJsonSteps) > 0 {
				background := formatter.backgroundByUri[pickle.Uri]
				jsonFeature.Elements = append(jsonFeature.Elements, jsonFeatureElement{
					Description: background.Description,
					Keyword:     background.Keyword,
					Line:        background.Location.Line,
					Steps:       backgroundJsonSteps,
					Type:        "background",
				})
			}

			pickleLine := pickle.Locations[0].Line
			scenarioID := fmt.Sprintf("%s;%s", jsonFeature.ID, makeId(scenario.Name))

			if len(scenario.Examples) > 0 {
				pickleLine = pickle.Locations[1].Line
				exampleKey := key(pickle.Uri, pickle.Locations[1])
				exampleRowIndex, ok := formatter.exampleRowIndexByKey[exampleKey]
				if !ok {
					return errors.New(fmt.Sprintf("No example row index for: %s", exampleKey))
				}
				example, eok := formatter.exampleByRowKey[exampleKey]
				if !eok {
					return errors.New(fmt.Sprintf("No example for: %s", exampleKey))
				}
				scenarioID = fmt.Sprintf(
					"%s;%s;%s;%d",
					jsonFeature.ID,
					makeId(scenario.Name),
					makeId(example.Name),
					exampleRowIndex)
			}

			scenarioTags := make([]jsonTag, len(pickle.Tags))
			for tagIndex, tag := range pickle.Tags {
				scenarioTags[tagIndex] = jsonTag{
					Line: tag.Location.Line,
					Name: tag.Name,
				}
			}

			jsonFeature.Elements = append(jsonFeature.Elements, jsonFeatureElement{
				Description: scenario.Description,
				ID:          scenarioID,
				Keyword:     scenario.Keyword,
				Line:        pickleLine,
				Name:        scenario.Name,
				Steps:       scenarioJsonSteps,
				Type:        "scenario",
				Tags:        scenarioTags,
			})

		case *messages.Envelope_TestStepMatched:
			pickle := formatter.pickleById[m.TestStepMatched.PickleId]
			pickleStep := pickle.Steps[m.TestStepMatched.Index]
			step := formatter.jsonStepsByKey[key(pickle.Uri, pickleStep.Locations[0])]

			step.Match = &jsonStepMatch{
				Location: fmt.Sprintf(
					"%s:%d",
					m.TestStepMatched.StepDefinitionReference.Uri,
					m.TestStepMatched.StepDefinitionReference.Location.Line,
				),
			}

		case *messages.Envelope_TestStepFinished:
			pickle := formatter.pickleById[m.TestStepFinished.PickleId]
			pickleStep := pickle.Steps[m.TestStepFinished.Index]
			step := formatter.jsonStepsByKey[key(pickle.Uri, pickleStep.Locations[0])]

			status := strings.ToLower(m.TestStepFinished.TestResult.Status.String())
			step.Result = &jsonStepResult{
				Duration:     durationToNanos(m.TestStepFinished.TestResult.Duration),
				Status:       status,
				ErrorMessage: m.TestStepFinished.TestResult.Message,
			}
		}
	}

	output, _ := json.MarshalIndent(formatter.jsonFeatures, "", "  ")
	_, err = fmt.Fprintln(stdout, string(output))
	return err
}

func (formatter *Formatter) findOrCreateJsonFeature(pickle *messages.Pickle) *jsonFeature {
	jFeature, ok := formatter.jsonFeaturesByURI[pickle.Uri]
	if !ok {
		gherkinDocumentFeature := formatter.gherkinDocumentByURI[pickle.Uri].Feature

		jFeature = &jsonFeature{
			Description: gherkinDocumentFeature.Description,
			Elements:    make([]jsonFeatureElement, 0),
			ID:          makeId(gherkinDocumentFeature.Name),
			Keyword:     gherkinDocumentFeature.Keyword,
			Line:        gherkinDocumentFeature.Location.Line,
			Name:        gherkinDocumentFeature.Name,
			URI:         pickle.Uri,
			Tags:        make([]jsonTag, len(gherkinDocumentFeature.Tags)),
		}

		for tagIndex, tag := range gherkinDocumentFeature.Tags {
			jFeature.Tags[tagIndex] = jsonTag{
				Line: tag.Location.Line,
				Name: tag.Name,
			}
		}

		formatter.jsonFeaturesByURI[pickle.Uri] = jFeature
		formatter.jsonFeatures = append(formatter.jsonFeatures, jFeature)
	}
	return jFeature
}

func key(uri string, location *messages.Location) string {
	return fmt.Sprintf("%s:%d", uri, location.Line)
}

func makeId(s string) string {
	return strings.ToLower(strings.Replace(s, " ", "-", -1))
}

func durationToNanos(d *messages.Duration) uint64 {
	return uint64(d.Seconds*1000000000 + int64(d.Nanos))
}
<commit_msg>Consistent use of pointers<commit_after>package json

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"strings"

	messages "github.com/cucumber/cucumber-messages-go/v6"
	gio "github.com/gogo/protobuf/io"
)

type jsonFeature struct {
	Description string                `json:"description"`
	Elements    []*jsonFeatureElement `json:"elements"`
	ID          string                `json:"id"`
	Keyword     string                `json:"keyword"`
	Line        uint32                `json:"line"`
	Name        string                `json:"name"`
	URI         string                `json:"uri"`
	Tags        []*jsonTag            `json:"tags,omitempty"`
}

type jsonFeatureElement struct {
	Description string      `json:"description"`
	ID          string      `json:"id,omitempty"`
	Keyword     string      `json:"keyword"`
	Line        uint32      `json:"line"`
	Name        string      `json:"name"`
	Steps       []*jsonStep `json:"steps"`
	Type        string      `json:"type"`
	Tags        []*jsonTag  `json:"tags,omitempty"`
}

type jsonStep struct {
	Keyword   string              `json:"keyword"`
	Line      uint32              `json:"line"`
	Name      string              `json:"name"`
	Result    *jsonStepResult     `json:"result"`
	Match     *jsonStepMatch      `json:"match,omitempty"`
	DocString *jsonDocString      `json:"doc_string,omitempty"`
	Rows      []*jsonDatatableRow `json:"rows,omitempty"`
}

type jsonDocString struct {
	ContentType string `json:"content_type"`
	Line        uint32 `json:"line"`
	Value       string `json:"value"`
}

type jsonDatatableRow struct {
	Cells []string `json:"cells"`
}

type jsonStepResult struct {
	Duration     uint64 `json:"duration,omitempty"`
	Status       string `json:"status"`
	ErrorMessage string `json:"error_message,omitempty"`
}

type jsonStepMatch struct {
	Location string `json:"location"`
}

type jsonTag struct {
	Line uint32 `json:"line"`
	Name string `json:"name"`
}

type Formatter struct {
	backgroundByUri      map[string]*messages.GherkinDocument_Feature_Background
	backgroundStepsByKey map[string]*messages.GherkinDocument_Feature_Step
	exampleByRowKey      map[string]*messages.GherkinDocument_Feature_Scenario_Examples
	exampleRowIndexByKey map[string]int
	gherkinDocumentByURI map[string]*messages.GherkinDocument
	jsonFeatures         []*jsonFeature
	jsonFeaturesByURI    map[string]*jsonFeature
	jsonStepsByKey       map[string]*jsonStep
	pickleById           map[string]*messages.Pickle
	scenariosByKey       map[string]*messages.GherkinDocument_Feature_Scenario
	scenarioStepsByKey   map[string]*messages.GherkinDocument_Feature_Step
}

// ProcessMessages writes a JSON report to STDOUT
func (formatter *Formatter) ProcessMessages(stdin io.Reader, stdout io.Writer) (err error) {
	formatter.jsonFeatures = make([]*jsonFeature, 0)
	formatter.jsonFeaturesByURI = make(map[string]*jsonFeature)
	formatter.jsonStepsByKey = make(map[string]*jsonStep)

	formatter.backgroundByUri = make(map[string]*messages.GherkinDocument_Feature_Background)
	formatter.backgroundStepsByKey = make(map[string]*messages.GherkinDocument_Feature_Step)
	formatter.exampleByRowKey = make(map[string]*messages.GherkinDocument_Feature_Scenario_Examples)
	formatter.exampleRowIndexByKey = make(map[string]int)
	formatter.gherkinDocumentByURI = make(map[string]*messages.GherkinDocument)
	formatter.pickleById = make(map[string]*messages.Pickle)
	formatter.scenariosByKey = make(map[string]*messages.GherkinDocument_Feature_Scenario)
	formatter.scenarioStepsByKey = make(map[string]*messages.GherkinDocument_Feature_Step)

	r := gio.NewDelimitedReader(stdin, 4096)

	for {
		wrapper := &messages.Envelope{}
		err := r.ReadMsg(wrapper)
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		switch m := wrapper.Message.(type) {
		case *messages.Envelope_GherkinDocument:
			formatter.gherkinDocumentByURI[m.GherkinDocument.Uri] = m.GherkinDocument
			for _, child := range m.GherkinDocument.Feature.Children {
				if child.GetBackground() != nil {
					formatter.backgroundByUri[m.GherkinDocument.Uri] = child.GetBackground()
					for _, step := range child.GetBackground().Steps {
						formatter.backgroundStepsByKey[key(m.GherkinDocument.Uri, step.Location)] = step
					}
				}

				if child.GetScenario() != nil {
					formatter.scenariosByKey[key(m.GherkinDocument.Uri, child.GetScenario().Location)] = child.GetScenario()
					for _, step := range child.GetScenario().Steps {
						formatter.scenarioStepsByKey[key(m.GherkinDocument.Uri, step.Location)] = step
					}

					for _, example := range child.GetScenario().Examples {
						for rowIndex, row := range example.TableBody {
							rowKey := key(m.GherkinDocument.Uri, row.Location)
							formatter.exampleByRowKey[rowKey] = example
							// Add 1 for the row header, and another 1 because the id is 1-based
							formatter.exampleRowIndexByKey[rowKey] = rowIndex + 2
						}
					}
				}
			}

		case *messages.Envelope_Pickle:
			pickle := m.Pickle
			formatter.pickleById[pickle.Id] = pickle
			jsonFeature := formatter.findOrCreateJsonFeature(pickle)

			scenario := formatter.scenariosByKey[key(pickle.Uri, pickle.Locations[0])]

			scenarioJsonSteps := make([]*jsonStep, 0)
			backgroundJsonSteps := make([]*jsonStep, 0)

			for _, pickleStep := range pickle.Steps {
				isBackgroundStep := false
				step := formatter.scenarioStepsByKey[key(pickle.Uri, pickleStep.Locations[0])]

				if step == nil {
					step = formatter.backgroundStepsByKey[key(pickle.Uri, pickleStep.Locations[0])]
					isBackgroundStep = true
				}

				jsonStep := &jsonStep{
					Keyword: step.Keyword,
					Line:    step.Location.Line,
					Name:    pickleStep.Text,
					// The match field defaults to the Gherkin step itself for some curious reason
					Match: &jsonStepMatch{
						Location: fmt.Sprintf("%s:%d", pickle.Uri, pickleStep.Locations[len(pickleStep.Locations)-1].Line),
					},
				}
				if isBackgroundStep {
					backgroundJsonSteps = append(backgroundJsonSteps, jsonStep)
				} else {
					scenarioJsonSteps = append(scenarioJsonSteps, jsonStep)
				}

				docString := step.GetDocString()
				if docString != nil {
					jsonStep.DocString = &jsonDocString{
						Line:        docString.Location.Line,
						ContentType: docString.ContentType,
						Value:       docString.Content,
					}
				}

				datatable := step.GetDataTable()
				if datatable != nil {
					jsonStep.Rows = make([]*jsonDatatableRow, len(datatable.GetRows()))
					for rowIndex, row := range datatable.GetRows() {
						cells := make([]string, len(row.Cells))
						for cellIndex, cell := range row.Cells {
							cells[cellIndex] = cell.Value
						}

						jsonStep.Rows[rowIndex] = &jsonDatatableRow{
							Cells: cells,
						}
					}
				}

				formatter.jsonStepsByKey[key(pickle.Uri, step.Location)] = jsonStep
			}

			if len(backgroundJsonSteps) > 0 {
				background := formatter.backgroundByUri[pickle.Uri]
				jsonFeature.Elements = append(jsonFeature.Elements, &jsonFeatureElement{
					Description: background.Description,
					Keyword:     background.Keyword,
					Line:        background.Location.Line,
					Steps:       backgroundJsonSteps,
					Type:        "background",
				})
			}

			pickleLine := pickle.Locations[0].Line
			scenarioID := fmt.Sprintf("%s;%s", jsonFeature.ID, makeId(scenario.Name))

			if len(scenario.Examples) > 0 {
				pickleLine = pickle.Locations[1].Line
				exampleKey := key(pickle.Uri, pickle.Locations[1])
				exampleRowIndex, ok := formatter.exampleRowIndexByKey[exampleKey]
				if !ok {
					return errors.New(fmt.Sprintf("No example row index for: %s", exampleKey))
				}
				example, eok := formatter.exampleByRowKey[exampleKey]
				if !eok {
					return errors.New(fmt.Sprintf("No example for: %s", exampleKey))
				}
				scenarioID = fmt.Sprintf(
					"%s;%s;%s;%d",
					jsonFeature.ID,
					makeId(scenario.Name),
					makeId(example.Name),
					exampleRowIndex)
			}

			scenarioTags := make([]*jsonTag, len(pickle.Tags))
			for tagIndex, tag := range pickle.Tags {
				scenarioTags[tagIndex] = &jsonTag{
					Line: tag.Location.Line,
					Name: tag.Name,
				}
			}

			jsonFeature.Elements = append(jsonFeature.Elements, &jsonFeatureElement{
				Description: scenario.Description,
				ID:          scenarioID,
				Keyword:     scenario.Keyword,
				Line:        pickleLine,
				Name:        scenario.Name,
				Steps:       scenarioJsonSteps,
				Type:        "scenario",
				Tags:        scenarioTags,
			})

		case *messages.Envelope_TestStepMatched:
			pickle := formatter.pickleById[m.TestStepMatched.PickleId]
			pickleStep := pickle.Steps[m.TestStepMatched.Index]
			step := formatter.jsonStepsByKey[key(pickle.Uri, pickleStep.Locations[0])]

			step.Match = &jsonStepMatch{
				Location: fmt.Sprintf(
					"%s:%d",
					m.TestStepMatched.StepDefinitionReference.Uri,
					m.TestStepMatched.StepDefinitionReference.Location.Line,
				),
			}

		case *messages.Envelope_TestStepFinished:
			pickle := formatter.pickleById[m.TestStepFinished.PickleId]
			pickleStep := pickle.Steps[m.TestStepFinished.Index]
			step := formatter.jsonStepsByKey[key(pickle.Uri, pickleStep.Locations[0])]

			status := strings.ToLower(m.TestStepFinished.TestResult.Status.String())
			step.Result = &jsonStepResult{
				Duration:     durationToNanos(m.TestStepFinished.TestResult.Duration),
				Status:       status,
				ErrorMessage: m.TestStepFinished.TestResult.Message,
			}
		}
	}

	output, _ := json.MarshalIndent(formatter.jsonFeatures, "", "  ")
	_, err = fmt.Fprintln(stdout, string(output))
	return err
}

func (formatter *Formatter) findOrCreateJsonFeature(pickle *messages.Pickle) *jsonFeature {
	jFeature, ok := formatter.jsonFeaturesByURI[pickle.Uri]
	if !ok {
		gherkinDocumentFeature := formatter.gherkinDocumentByURI[pickle.Uri].Feature

		jFeature = &jsonFeature{
			Description: gherkinDocumentFeature.Description,
			Elements:    make([]*jsonFeatureElement, 0),
			ID:          makeId(gherkinDocumentFeature.Name),
			Keyword:     gherkinDocumentFeature.Keyword,
			Line:        gherkinDocumentFeature.Location.Line,
			Name:        gherkinDocumentFeature.Name,
			URI:         pickle.Uri,
			Tags:        make([]*jsonTag, len(gherkinDocumentFeature.Tags)),
		}

		for tagIndex, tag := range gherkinDocumentFeature.Tags {
			jFeature.Tags[tagIndex] = &jsonTag{
				Line: tag.Location.Line,
				Name: tag.Name,
			}
		}

		formatter.jsonFeaturesByURI[pickle.Uri] = jFeature
		formatter.jsonFeatures = append(formatter.jsonFeatures, jFeature)
	}
	return jFeature
}

func key(uri string, location *messages.Location) string {
	return fmt.Sprintf("%s:%d", uri, location.Line)
}

func makeId(s string) string {
	return strings.ToLower(strings.Replace(s, " ", "-", -1))
}

func durationToNanos(d *messages.Duration) uint64 {
	return uint64(d.Seconds*1000000000 + int64(d.Nanos))
}
<|endoftext|>


<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

// gen runs go generate on Unicode- and CLDR-related package in the text
// repositories, taking into account dependencies and versions.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"unicode"

	"golang.org/x/text/internal/gen"
)

var (
	verbose     = flag.Bool("v", false, "verbose output")
	force       = flag.Bool("force", false, "ignore failing dependencies")
	excludeList = flag.String("exclude", "",
		"comma-separated list of packages to exclude")

	// The user can specify a selection of packages to build on the command line.
	args []string
)

func exclude(pkg string) bool {
	if len(args) > 0 {
		return !contains(args, pkg)
	}
	return contains(strings.Split(*excludeList, ","), pkg)
}

// TODO:
// - Better version handling.
// - Generate tables for the core unicode package?
// - Add generation for encodings. This requires some retooling here and there.
// - Running repo-wide "long" tests.

var vprintf = fmt.Printf

func main() {
	gen.Init()
	args = flag.Args()
	if !*verbose {
		// Set vprintf to a no-op.
		vprintf = func(string, ...interface{}) (int, error) { return 0, nil }
	}

	if gen.UnicodeVersion() != unicode.Version {
		fmt.Printf("Requested Unicode version %s; core unicode version is %s.\n",
			gen.UnicodeVersion,
			unicode.Version)
		// TODO: use collate to compare. Simple comparison will work, though,
		// until Unicode reaches version 10. To avoid circular dependencies, we
		// could use the NumericWeighter without using package collate using a
		// trivial Weighter implementation.
		if gen.UnicodeVersion() < unicode.Version && !*force {
			os.Exit(2)
		}
	}
	var (
		cldr     = generate("cldr")
		language = generate("language", cldr)
		norm     = generate("unicode/norm")
		_        = generate("unicode/rangetable")
		_        = generate("width")
		_        = generate("currency", cldr, language)
		_        = generate("display", cldr, language)
		_        = generate("cases", norm)
		_        = generate("collate", norm, cldr, language)
		_        = generate("search", norm, cldr, language)
	)
	all.Wait()

	if hasErrors {
		fmt.Println("FAIL")
		os.Exit(1)
	}
	vprintf("SUCCESS\n")
}

var (
	all       sync.WaitGroup
	hasErrors bool
)

type dependency struct {
	sync.WaitGroup
	hasErrors bool
}

func generate(pkg string, deps ...*dependency) *dependency {
	var wg dependency
	if exclude(pkg) {
		return &wg
	}
	wg.Add(1)
	all.Add(1)
	go func() {
		defer wg.Done()
		defer all.Done()
		// Wait for dependencies to finish.
		for _, d := range deps {
			d.Wait()
			if d.hasErrors && !*force {
				fmt.Printf("--- ABORT: %s\n", pkg)
				wg.hasErrors = true
				return
			}
		}
		vprintf("=== GENERATE %s\n", pkg)
		args := []string{"generate"}
		if *verbose {
			args = append(args, "-v")
		}
		args = append(args, "./"+pkg)
		cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
		w := &bytes.Buffer{}
		cmd.Stderr = w
		cmd.Stdout = w
		if err := cmd.Run(); err != nil {
			fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(w), err)
			hasErrors = true
			wg.hasErrors = true
			return
		}
		vprintf("--- SUCCESS: %s\n\t%v\n", pkg, indent(w))
	}()
	return &wg
}

func contains(a []string, s string) bool {
	for _, e := range a {
		if s == e {
			return true
		}
	}
	return false
}

func indent(b *bytes.Buffer) string {
	return strings.Replace(strings.TrimSpace(b.String()), "\n", "\n\t", -1)
}
<commit_msg>: Added depdendencies to top-level generator.<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

// gen runs go generate on Unicode- and CLDR-related package in the text
// repositories, taking into account dependencies and versions.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"unicode"

	"golang.org/x/text/internal/gen"
)

var (
	verbose     = flag.Bool("v", false, "verbose output")
	force       = flag.Bool("force", false, "ignore failing dependencies")
	excludeList = flag.String("exclude", "",
		"comma-separated list of packages to exclude")

	// The user can specify a selection of packages to build on the command line.
	args []string
)

func exclude(pkg string) bool {
	if len(args) > 0 {
		return !contains(args, pkg)
	}
	return contains(strings.Split(*excludeList, ","), pkg)
}

// TODO:
// - Better version handling.
// - Generate tables for the core unicode package?
// - Add generation for encodings. This requires some retooling here and there.
// - Running repo-wide "long" tests.

var vprintf = fmt.Printf

func main() {
	gen.Init()
	args = flag.Args()
	if !*verbose {
		// Set vprintf to a no-op.
		vprintf = func(string, ...interface{}) (int, error) { return 0, nil }
	}

	if gen.UnicodeVersion() != unicode.Version {
		fmt.Printf("Requested Unicode version %s; core unicode version is %s.\n",
			gen.UnicodeVersion,
			unicode.Version)
		// TODO: use collate to compare. Simple comparison will work, though,
		// until Unicode reaches version 10. To avoid circular dependencies, we
		// could use the NumericWeighter without using package collate using a
		// trivial Weighter implementation.
		if gen.UnicodeVersion() < unicode.Version && !*force {
			os.Exit(2)
		}
	}
	var (
		cldr     = generate("cldr")
		language = generate("language", cldr)
		internal = generate("internal", language)
		norm     = generate("unicode/norm")
		_        = generate("unicode/rangetable")
		_        = generate("width")
		_        = generate("currency", cldr, language, internal)
		_        = generate("display", cldr, language)
		_        = generate("cases", norm)
		_        = generate("collate", norm, cldr, language)
		_        = generate("search", norm, cldr, language)
	)
	all.Wait()

	if hasErrors {
		fmt.Println("FAIL")
		os.Exit(1)
	}
	vprintf("SUCCESS\n")
}

var (
	all       sync.WaitGroup
	hasErrors bool
)

type dependency struct {
	sync.WaitGroup
	hasErrors bool
}

func generate(pkg string, deps ...*dependency) *dependency {
	var wg dependency
	if exclude(pkg) {
		return &wg
	}
	wg.Add(1)
	all.Add(1)
	go func() {
		defer wg.Done()
		defer all.Done()
		// Wait for dependencies to finish.
		for _, d := range deps {
			d.Wait()
			if d.hasErrors && !*force {
				fmt.Printf("--- ABORT: %s\n", pkg)
				wg.hasErrors = true
				return
			}
		}
		vprintf("=== GENERATE %s\n", pkg)
		args := []string{"generate"}
		if *verbose {
			args = append(args, "-v")
		}
		args = append(args, "./"+pkg)
		cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
		w := &bytes.Buffer{}
		cmd.Stderr = w
		cmd.Stdout = w
		if err := cmd.Run(); err != nil {
			fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(w), err)
			hasErrors = true
			wg.hasErrors = true
			return
		}
		vprintf("--- SUCCESS: %s\n\t%v\n", pkg, indent(w))
	}()
	return &wg
}

func contains(a []string, s string) bool {
	for _, e := range a {
		if s == e {
			return true
		}
	}
	return false
}

func indent(b *bytes.Buffer) string {
	return strings.Replace(strings.TrimSpace(b.String()), "\n", "\n\t", -1)
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
// Licensed under the Mozilla Public License v2.0

package oci

import (
	"context"
	"fmt"
	"strconv"
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
	"github.com/oracle/oci-go-sdk/v29/common"
	oci_logging "github.com/oracle/oci-go-sdk/v29/logging"

	"github.com/terraform-providers/terraform-provider-oci/httpreplay"
)

var (
	CustomLogRequiredOnlyResource = LogResourceDependencies +
		generateResourceFromRepresentationMap("oci_logging_log", "test_log", Required, Create, customLogRepresentation)

	CustomLogResourceConfig = LogResourceDependencies +
		generateResourceFromRepresentationMap("oci_logging_log", "test_log", Optional, Update, customLogRepresentation)

	customLogDataSourceRepresentation = map[string]interface{}{
		"log_group_id": Representation{repType: Required, create: `${oci_logging_log_group.test_log_group.id}`, update: `${oci_logging_log_group.test_update_log_group.id}`},
		"display_name": Representation{repType: Optional, create: `displayName`, update: `displayName2`},
		"log_type":     Representation{repType: Optional, create: `CUSTOM`},
		"state":        Representation{repType: Optional, create: `ACTIVE`},
		"filter":       RepresentationGroup{Required, logDataSourceFilterRepresentation}}

	customLogRepresentation = map[string]interface{}{
		"display_name":       Representation{repType: Required, create: `log`, update: `displayName2`},
		"log_group_id":       Representation{repType: Required, create: `${oci_logging_log_group.test_log_group.id}`, update: `${oci_logging_log_group.test_update_log_group.id}`},
		"log_type":           Representation{repType: Required, create: `CUSTOM`},
		"defined_tags":       Representation{repType: Optional, create: `${map("${oci_identity_tag_namespace.tag-namespace1.name}.${oci_identity_tag.tag1.name}", "value")}`, update: `${map("${oci_identity_tag_namespace.tag-namespace1.name}.${oci_identity_tag.tag1.name}", "updatedValue")}`},
		"freeform_tags":      Representation{repType: Optional, create: map[string]string{"Department": "Finance"}, update: map[string]string{"Department": "Accounting"}},
		"is_enabled":         Representation{repType: Optional, create: `false`, update: `true`},
		"retention_duration": Representation{repType: Optional, create: `30`, update: `60`},
	}

	CustomLogResourceDependencies = DefinedTagsDependencies +
		generateResourceFromRepresentationMap("oci_logging_log_group", "test_log_group", Required, Create, logGroupRepresentation)
)

func TestLoggingCustomLogResource_basic(t *testing.T) {
	httpreplay.SetScenario("TestLoggingLogResource_basic")
	defer httpreplay.SaveScenario()

	provider := testAccProvider
	config := testProviderConfig()

	compartmentId := getEnvSettingWithBlankDefault("compartment_ocid")
	compartmentIdVariableStr := fmt.Sprintf("variable \"compartment_id\" { default = \"%s\" }\n", compartmentId)

	resourceName := "oci_logging_log.test_log"
	datasourceName := "data.oci_logging_logs.test_logs"
	singularDatasourceName := "data.oci_logging_log.test_log"

	var resId, resId2 string

	resource.Test(t, resource.TestCase{
		PreCheck: func() { testAccPreCheck(t) },
		Providers: map[string]terraform.ResourceProvider{
			"oci": provider,
		},
		CheckDestroy: testAccCheckLoggingCustomLogDestroy,
		Steps: []resource.TestStep{
			// verify create
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceDependencies +
					generateResourceFromRepresentationMap("oci_logging_log", "test_log", Required, Create, customLogRepresentation),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "display_name", "log"),
					resource.TestCheckResourceAttrSet(resourceName, "log_group_id"),
					resource.TestCheckResourceAttr(resourceName, "log_type", "CUSTOM"),

					func(s *terraform.State) (err error) {
						resId, err = fromInstanceState(s, resourceName, "id")
						return err
					},
				),
			},

			// delete before next create
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceDependencies,
			},
			// verify create with optionals
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceDependencies +
					generateResourceFromRepresentationMap("oci_logging_log", "test_log", Optional, Create, customLogRepresentation),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "defined_tags.%", "1"),
					resource.TestCheckResourceAttr(resourceName, "display_name", "log"),
					resource.TestCheckResourceAttr(resourceName, "freeform_tags.%", "1"),
					resource.TestCheckResourceAttrSet(resourceName, "id"),
					resource.TestCheckResourceAttr(resourceName, "is_enabled", "false"),
					resource.TestCheckResourceAttrSet(resourceName, "log_group_id"),
					resource.TestCheckResourceAttr(resourceName, "log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(resourceName, "retention_duration", "30"),
					resource.TestCheckResourceAttrSet(resourceName, "state"),

					func(s *terraform.State) (err error) {
						resId, err = fromInstanceState(s, resourceName, "id")
						if isEnableExportCompartment, _ := strconv.ParseBool(getEnvSettingWithDefault("enable_export_compartment", "false")); isEnableExportCompartment {
							if errExport := testExportCompartmentWithResourceName(&resId, &compartmentId, resourceName); errExport != nil {
								return errExport
							}
						}
						return err
					},
				),
			},

			// verify updates to updatable parameters
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceDependencies +
					generateResourceFromRepresentationMap("oci_logging_log", "test_log", Optional, Update, customLogRepresentation) +
					generateResourceFromRepresentationMap("oci_logging_log_group", "test_update_log_group", Required, Update, logGroupRepresentation),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "defined_tags.%", "1"),
					resource.TestCheckResourceAttr(resourceName, "display_name", "displayName2"),
					resource.TestCheckResourceAttr(resourceName, "freeform_tags.%", "1"),
					resource.TestCheckResourceAttrSet(resourceName, "id"),
					resource.TestCheckResourceAttr(resourceName, "is_enabled", "true"),
					resource.TestCheckResourceAttrSet(resourceName, "log_group_id"),
					resource.TestCheckResourceAttr(resourceName, "log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(resourceName, "retention_duration", "60"),
					resource.TestCheckResourceAttrSet(resourceName, "state"),

					func(s *terraform.State) (err error) {
						resId2, err = fromInstanceState(s, resourceName, "id")
						if resId != resId2 {
							return fmt.Errorf("Resource recreated when it was supposed to be updated.")
						}
						return err
					},
				),
			},
			// verify datasource
			{
				Config: config +
					generateDataSourceFromRepresentationMap("oci_logging_logs", "test_logs", Optional, Update, customLogDataSourceRepresentation) +
					generateResourceFromRepresentationMap("oci_logging_log_group", "test_update_log_group", Required, Update, logGroupRepresentation) +
					compartmentIdVariableStr + CustomLogResourceDependencies +
					generateResourceFromRepresentationMap("oci_logging_log", "test_log", Optional, Update, customLogRepresentation),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(datasourceName, "display_name", "displayName2"),
					resource.TestCheckResourceAttrSet(datasourceName, "log_group_id"),
					resource.TestCheckResourceAttr(datasourceName, "log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(datasourceName, "state", "ACTIVE"),
					resource.TestCheckResourceAttr(datasourceName, "logs.#", "1"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.compartment_id"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.defined_tags.%", "1"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.display_name", "displayName2"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.freeform_tags.%", "1"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.id"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.is_enabled", "true"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.log_group_id"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.retention_duration", "60"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.state"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.time_created"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.time_last_modified"),
				),
			},
			// verify singular datasource
			{
				Config: config +
					generateDataSourceFromRepresentationMap("oci_logging_log", "test_log", Required, Create, logSingularDataSourceRepresentation) +
					compartmentIdVariableStr + CustomLogResourceConfig,
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttrSet(singularDatasourceName, "log_group_id"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "log_id"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "compartment_id"),
					resource.TestCheckResourceAttr(singularDatasourceName, "defined_tags.%", "1"),
					resource.TestCheckResourceAttr(singularDatasourceName, "display_name", "displayName2"),
					resource.TestCheckResourceAttr(singularDatasourceName, "freeform_tags.%", "1"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "id"),
					resource.TestCheckResourceAttr(singularDatasourceName, "is_enabled", "true"),
					resource.TestCheckResourceAttr(singularDatasourceName, "log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(singularDatasourceName, "retention_duration", "60"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "state"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "tenancy_id"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "time_created"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "time_last_modified"),
				),
			},
			// remove singular datasource from previous step so that it doesn't conflict with import tests
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceConfig,
			},
			// verify resource import
			{
				Config:                  config,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{},
				ImportStateIdFunc:       GetLogResourceCompositeId(resourceName),
				ResourceName:            resourceName,
			},
		},
	})
}

func testAccCheckLoggingCustomLogDestroy(s *terraform.State) error {
	noResourceFound := true
	client := testAccProvider.Meta().(*OracleClients).loggingManagementClient()
	for _, rs := range s.RootModule().Resources {
		if rs.Type == "oci_logging_log" {
			noResourceFound = false
			request := oci_logging.GetLogRequest{}

			if value, ok := rs.Primary.Attributes["log_group_id"]; ok {
				request.LogGroupId = &value
			}

			tmp := rs.Primary.ID
			request.LogId = &tmp

			request.RequestMetadata.RetryPolicy = getRetryPolicy(true, "logging")

			_, err := client.GetLog(context.Background(), request)

			if err == nil {
				return fmt.Errorf("resource still exists")
			}

			//Verify that exception is for '404 not found'.
			if failure, isServiceError := common.IsServiceError(err); !isServiceError || failure.GetHTTPStatusCode() != 404 {
				return err
			}
		}
	}
	if noResourceFound {
		return fmt.Errorf("at least one resource was expected from the state file, but could not be found")
	}

	return nil
}

func init() {
	if DependencyGraph == nil {
		initDependencyGraph()
	}
	if !inSweeperExcludeList("CustomLoggingLog") {
		resource.AddTestSweepers("CustomLoggingLog", &resource.Sweeper{
			Name:         "CustomLoggingLog",
			Dependencies: DependencyGraph["log"],
			F:            sweepLoggingCustomLogResource,
		})
	}
}

func sweepLoggingCustomLogResource(compartment string) error {
	loggingManagementClient := GetTestClients(&schema.ResourceData{}).loggingManagementClient()
	logIds, err := getLogIds(compartment)
	if err != nil {
		return err
	}
	for _, logId := range logIds {
		if ok := SweeperDefaultResourceId[logId]; !ok {
			deleteLogRequest := oci_logging.DeleteLogRequest{}

			deleteLogRequest.LogId = &logId

			deleteLogRequest.RequestMetadata.RetryPolicy = getRetryPolicy(true, "logging")
			_, error := loggingManagementClient.DeleteLog(context.Background(), deleteLogRequest)
			if error != nil {
				fmt.Printf("Error deleting Log %s %s, It is possible that the resource is already deleted. Please verify manually \n", logId, error)
				continue
			}
		}
	}
	return nil
}
<commit_msg>Test fix for custom logs<commit_after>// Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
// Licensed under the Mozilla Public License v2.0

package oci

import (
	"context"
	"fmt"
	"strconv"
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
	"github.com/oracle/oci-go-sdk/v29/common"
	oci_logging "github.com/oracle/oci-go-sdk/v29/logging"

	"github.com/terraform-providers/terraform-provider-oci/httpreplay"
)

var (
	CustomLogRequiredOnlyResource = LogResourceDependencies +
		generateResourceFromRepresentationMap("oci_logging_log", "test_log", Required, Create, customLogRepresentation)

	CustomLogResourceConfig = LogResourceDependencies +
		generateResourceFromRepresentationMap("oci_logging_log", "test_log", Optional, Update, customLogRepresentation)

	customLogDataSourceRepresentation = map[string]interface{}{
		"log_group_id": Representation{repType: Required, create: `${oci_logging_log_group.test_log_group.id}`, update: `${oci_logging_log_group.test_update_log_group.id}`},
		"display_name": Representation{repType: Optional, create: `displayName`, update: `displayName2`},
		"log_type":     Representation{repType: Optional, create: `CUSTOM`},
		"state":        Representation{repType: Optional, create: `ACTIVE`},
		"filter":       RepresentationGroup{Required, logDataSourceFilterRepresentation}}

	customLogRepresentation = map[string]interface{}{
		"display_name":       Representation{repType: Required, create: `log`, update: `displayName2`},
		"log_group_id":       Representation{repType: Required, create: `${oci_logging_log_group.test_log_group.id}`, update: `${oci_logging_log_group.test_update_log_group.id}`},
		"log_type":           Representation{repType: Required, create: `CUSTOM`},
		"defined_tags":       Representation{repType: Optional, create: `${map("${oci_identity_tag_namespace.tag-namespace1.name}.${oci_identity_tag.tag1.name}", "value")}`, update: `${map("${oci_identity_tag_namespace.tag-namespace1.name}.${oci_identity_tag.tag1.name}", "updatedValue")}`},
		"freeform_tags":      Representation{repType: Optional, create: map[string]string{"Department": "Finance"}, update: map[string]string{"Department": "Accounting"}},
		"is_enabled":         Representation{repType: Optional, create: `false`, update: `true`},
		"retention_duration": Representation{repType: Optional, create: `30`, update: `60`},
	}

	CustomLogResourceDependencies = DefinedTagsDependencies +
		generateResourceFromRepresentationMap("oci_logging_log_group", "test_log_group", Required, Create, logGroupRepresentation)
)

func TestLoggingCustomLogResource_basic(t *testing.T) {
	httpreplay.SetScenario("TestLoggingLogResource_basic")
	defer httpreplay.SaveScenario()

	provider := testAccProvider
	config := testProviderConfig()

	compartmentId := getEnvSettingWithBlankDefault("compartment_ocid")
	compartmentIdVariableStr := fmt.Sprintf("variable \"compartment_id\" { default = \"%s\" }\n", compartmentId)

	resourceName := "oci_logging_log.test_log"
	datasourceName := "data.oci_logging_logs.test_logs"
	singularDatasourceName := "data.oci_logging_log.test_log"

	var compositeId string
	var resId, resId2 string

	resource.Test(t, resource.TestCase{
		PreCheck: func() { testAccPreCheck(t) },
		Providers: map[string]terraform.ResourceProvider{
			"oci": provider,
		},
		CheckDestroy: testAccCheckLoggingCustomLogDestroy,
		Steps: []resource.TestStep{
			// verify create
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceDependencies +
					generateResourceFromRepresentationMap("oci_logging_log", "test_log", Required, Create, customLogRepresentation),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "display_name", "log"),
					resource.TestCheckResourceAttrSet(resourceName, "log_group_id"),
					resource.TestCheckResourceAttr(resourceName, "log_type", "CUSTOM"),

					func(s *terraform.State) (err error) {
						resId, err = fromInstanceState(s, resourceName, "id")
						return err
					},
				),
			},

			// delete before next create
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceDependencies,
			},
			// verify create with optionals
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceDependencies +
					generateResourceFromRepresentationMap("oci_logging_log", "test_log", Optional, Create, customLogRepresentation),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "defined_tags.%", "1"),
					resource.TestCheckResourceAttr(resourceName, "display_name", "log"),
					resource.TestCheckResourceAttr(resourceName, "freeform_tags.%", "1"),
					resource.TestCheckResourceAttrSet(resourceName, "id"),
					resource.TestCheckResourceAttr(resourceName, "is_enabled", "false"),
					resource.TestCheckResourceAttrSet(resourceName, "log_group_id"),
					resource.TestCheckResourceAttr(resourceName, "log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(resourceName, "retention_duration", "30"),
					resource.TestCheckResourceAttrSet(resourceName, "state"),

					func(s *terraform.State) (err error) {
						resId, err = fromInstanceState(s, resourceName, "id")
						if isEnableExportCompartment, _ := strconv.ParseBool(getEnvSettingWithDefault("enable_export_compartment", "false")); isEnableExportCompartment {
							logGroupId, _ := fromInstanceState(s, resourceName, "log_group_id")
							compositeId = getLogCompositeId(logGroupId, resId)
							if errExport := testExportCompartmentWithResourceName(&compositeId, &compartmentId, resourceName); errExport != nil {
								return errExport
							}
						}
						return err
					},
				),
			},

			// verify updates to updatable parameters
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceDependencies +
					generateResourceFromRepresentationMap("oci_logging_log", "test_log", Optional, Update, customLogRepresentation) +
					generateResourceFromRepresentationMap("oci_logging_log_group", "test_update_log_group", Required, Update, logGroupRepresentation),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "defined_tags.%", "1"),
					resource.TestCheckResourceAttr(resourceName, "display_name", "displayName2"),
					resource.TestCheckResourceAttr(resourceName, "freeform_tags.%", "1"),
					resource.TestCheckResourceAttrSet(resourceName, "id"),
					resource.TestCheckResourceAttr(resourceName, "is_enabled", "true"),
					resource.TestCheckResourceAttrSet(resourceName, "log_group_id"),
					resource.TestCheckResourceAttr(resourceName, "log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(resourceName, "retention_duration", "60"),
					resource.TestCheckResourceAttrSet(resourceName, "state"),

					func(s *terraform.State) (err error) {
						resId2, err = fromInstanceState(s, resourceName, "id")
						if resId != resId2 {
							return fmt.Errorf("Resource recreated when it was supposed to be updated.")
						}
						return err
					},
				),
			},
			// verify datasource
			{
				Config: config +
					generateDataSourceFromRepresentationMap("oci_logging_logs", "test_logs", Optional, Update, customLogDataSourceRepresentation) +
					generateResourceFromRepresentationMap("oci_logging_log_group", "test_update_log_group", Required, Update, logGroupRepresentation) +
					compartmentIdVariableStr + CustomLogResourceDependencies +
					generateResourceFromRepresentationMap("oci_logging_log", "test_log", Optional, Update, customLogRepresentation),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(datasourceName, "display_name", "displayName2"),
					resource.TestCheckResourceAttrSet(datasourceName, "log_group_id"),
					resource.TestCheckResourceAttr(datasourceName, "log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(datasourceName, "state", "ACTIVE"),
					resource.TestCheckResourceAttr(datasourceName, "logs.#", "1"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.compartment_id"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.defined_tags.%", "1"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.display_name", "displayName2"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.freeform_tags.%", "1"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.id"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.is_enabled", "true"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.log_group_id"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(datasourceName, "logs.0.retention_duration", "60"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.state"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.time_created"),
					resource.TestCheckResourceAttrSet(datasourceName, "logs.0.time_last_modified"),
				),
			},
			// verify singular datasource
			{
				Config: config +
					generateDataSourceFromRepresentationMap("oci_logging_log", "test_log", Required, Create, logSingularDataSourceRepresentation) +
					compartmentIdVariableStr + CustomLogResourceConfig,
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttrSet(singularDatasourceName, "log_group_id"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "log_id"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "compartment_id"),
					resource.TestCheckResourceAttr(singularDatasourceName, "defined_tags.%", "1"),
					resource.TestCheckResourceAttr(singularDatasourceName, "display_name", "displayName2"),
					resource.TestCheckResourceAttr(singularDatasourceName, "freeform_tags.%", "1"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "id"),
					resource.TestCheckResourceAttr(singularDatasourceName, "is_enabled", "true"),
					resource.TestCheckResourceAttr(singularDatasourceName, "log_type", "CUSTOM"),
					resource.TestCheckResourceAttr(singularDatasourceName, "retention_duration", "60"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "state"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "tenancy_id"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "time_created"),
					resource.TestCheckResourceAttrSet(singularDatasourceName, "time_last_modified"),
				),
			},
			// remove singular datasource from previous step so that it doesn't conflict with import tests
			{
				Config: config + compartmentIdVariableStr + CustomLogResourceConfig,
			},
			// verify resource import
			{
				Config:                  config,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{},
				ImportStateIdFunc:       GetLogResourceCompositeId(resourceName),
				ResourceName:            resourceName,
			},
		},
	})
}

func testAccCheckLoggingCustomLogDestroy(s *terraform.State) error {
	noResourceFound := true
	client := testAccProvider.Meta().(*OracleClients).loggingManagementClient()
	for _, rs := range s.RootModule().Resources {
		if rs.Type == "oci_logging_log" {
			noResourceFound = false
			request := oci_logging.GetLogRequest{}

			if value, ok := rs.Primary.Attributes["log_group_id"]; ok {
				request.LogGroupId = &value
			}

			tmp := rs.Primary.ID
			request.LogId = &tmp

			request.RequestMetadata.RetryPolicy = getRetryPolicy(true, "logging")

			_, err := client.GetLog(context.Background(), request)

			if err == nil {
				return fmt.Errorf("resource still exists")
			}

			//Verify that exception is for '404 not found'.
			if failure, isServiceError := common.IsServiceError(err); !isServiceError || failure.GetHTTPStatusCode() != 404 {
				return err
			}
		}
	}
	if noResourceFound {
		return fmt.Errorf("at least one resource was expected from the state file, but could not be found")
	}

	return nil
}

func init() {
	if DependencyGraph == nil {
		initDependencyGraph()
	}
	if !inSweeperExcludeList("CustomLoggingLog") {
		resource.AddTestSweepers("CustomLoggingLog", &resource.Sweeper{
			Name:         "CustomLoggingLog",
			Dependencies: DependencyGraph["log"],
			F:            sweepLoggingCustomLogResource,
		})
	}
}

func sweepLoggingCustomLogResource(compartment string) error {
	loggingManagementClient := GetTestClients(&schema.ResourceData{}).loggingManagementClient()
	logIds, err := getLogIds(compartment)
	if err != nil {
		return err
	}
	for _, logId := range logIds {
		if ok := SweeperDefaultResourceId[logId]; !ok {
			deleteLogRequest := oci_logging.DeleteLogRequest{}

			deleteLogRequest.LogId = &logId

			deleteLogRequest.RequestMetadata.RetryPolicy = getRetryPolicy(true, "logging")
			_, error := loggingManagementClient.DeleteLog(context.Background(), deleteLogRequest)
			if error != nil {
				fmt.Printf("Error deleting Log %s %s, It is possible that the resource is already deleted. Please verify manually \n", logId, error)
				continue
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package godruid

import (
	"encoding/json"
)

// Check http://druid.io/docs/0.6.154/Querying.html#query-operators for detail description.

// The Query interface stands for any kinds of druid query.
type Query interface {
	setup()
	onResponse(content []byte) error
}

// ---------------------------------
// GroupBy Query
// ---------------------------------

type QueryGroupBy struct {
	QueryType        string                 `json:"queryType"`
	DataSource       string                 `json:"dataSource"`
	Dimensions       []DimSpec              `json:"dimensions"`
	Granularity      Granlarity             `json:"granularity"`
	LimitSpec        *Limit                 `json:"limitSpec,omitempty"`
	Having           *Having                `json:"having,omitempty"`
	Filter           *Filter                `json:"filter,omitempty"`
	Aggregations     []Aggregation          `json:"aggregations"`
	PostAggregations []PostAggregation      `json:"postAggregations,omitempty"`
	Intervals        []string               `json:"intervals"`
	Context          map[string]interface{} `json:"context,omitempty"`

	QueryResult []GroupbyItem `json:"-"`
}

type GroupbyItem struct {
	Version   string                 `json:"version"`
	Timestamp string                 `json:"timestamp"`
	Event     map[string]interface{} `json:"event"`
}

func (q *QueryGroupBy) setup() { q.QueryType = "groupBy" }
func (q *QueryGroupBy) onResponse(content []byte) error {
	res := new([]GroupbyItem)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// Search Query
// ---------------------------------

type QuerySearch struct {
	QueryType        string                 `json:"queryType"`
	DataSource       string                 `json:"dataSource"`
	Granularity      Granlarity             `json:"granularity"`
	Filter           *Filter                `json:"filter,omitempty"`
	Intervals        []string               `json:"intervals"`
	SearchDimensions []string               `json:"searchDimensions,omitempty"`
	Query            *SearchQuery           `json:"query"`
	Sort             *SearchSort            `json:"sort"`
	Context          map[string]interface{} `json:"context,omitempty"`

	QueryResult []SearchItem `json:"-"`
}

type SearchItem struct {
	Timestamp string     `json:"timestamp"`
	Result    []DimValue `json:"result"`
}

type DimValue struct {
	Dimension string `json:"dimension"`
	Value     string `json:"value"`
}

func (q *QuerySearch) setup() { q.QueryType = "search" }
func (q *QuerySearch) onResponse(content []byte) error {
	res := new([]SearchItem)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// SegmentMetadata Query
// ---------------------------------

type QuerySegmentMetadata struct {
	QueryType  string                 `json:"queryType"`
	DataSource string                 `json:"dataSource"`
	Intervals  []string               `json:"intervals"`
	ToInclude  *ToInclude             `json:"toInclude,omitempty"`
	Merge      interface{}            `json:"merge,omitempty"`
	Context    map[string]interface{} `json:"context,omitempty"`

	QueryResult []SegmentMetaData `json:"-"`
}

type SegmentMetaData struct {
	Id        string                `json:"id"`
	Intervals []string              `json:"intervals"`
	Columns   map[string]ColumnItem `json:"columns"`
}

type ColumnItem struct {
	Type        string      `json:"type"`
	Size        int         `json:"size"`
	Cardinality interface{} `json:"cardinality"`
}

func (q *QuerySegmentMetadata) setup() { q.QueryType = "segmentMetadata" }
func (q *QuerySegmentMetadata) onResponse(content []byte) error {
	res := new([]SegmentMetaData)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// TimeBoundary Query
// ---------------------------------

type QueryTimeBoundary struct {
	QueryType  string                 `json:"queryType"`
	DataSource string                 `json:"dataSource"`
	Bound      string                 `json:"bound,omitempty"`
	Filter     *Filter                `json:"filter,omitempty"`
	Context    map[string]interface{} `json:"context,omitempty"`

	QueryResult []TimeBoundaryItem `json:"-"`
}

type TimeBoundaryItem struct {
	Timestamp string       `json:"timestamp"`
	Result    TimeBoundary `json:"result"`
}

type TimeBoundary struct {
	MinTime string `json:"minTime"`
	MaxTime string `json:"maxTime"`
}

func (q *QueryTimeBoundary) setup() { q.QueryType = "timeBoundary" }
func (q *QueryTimeBoundary) onResponse(content []byte) error {
	res := new([]TimeBoundaryItem)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// Timeseries Query
// ---------------------------------

type QueryTimeseries struct {
	QueryType        string                 `json:"queryType"`
	DataSource       string                 `json:"dataSource"`
	Granularity      Granlarity             `json:"granularity"`
	Filter           *Filter                `json:"filter,omitempty"`
	Aggregations     []Aggregation          `json:"aggregations"`
	PostAggregations []PostAggregation      `json:"postAggregations,omitempty"`
	Intervals        []string               `json:"intervals"`
	Context          map[string]interface{} `json:"context,omitempty"`

	QueryResult []Timeseries `json:"-"`
}

type Timeseries struct {
	Timestamp string                 `json:"timestamp"`
	Result    map[string]interface{} `json:"result"`
}

func (q *QueryTimeseries) setup() { q.QueryType = "timeseries" }
func (q *QueryTimeseries) onResponse(content []byte) error {
	res := new([]Timeseries)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// TopN Query
// ---------------------------------

type QueryTopN struct {
	QueryType        string                 `json:"queryType"`
	DataSource       string                 `json:"dataSource"`
	Granularity      Granlarity             `json:"granularity"`
	Dimension        DimSpec                `json:"dimension"`
	Threshold        int                    `json:"threshold"`
	Metric           *TopNMetric            `json:"metric"`
	Filter           *Filter                `json:"filter,omitempty"`
	Aggregations     []Aggregation          `json:"aggregations"`
	PostAggregations []PostAggregation      `json:"postAggregations,omitempty"`
	Intervals        []string               `json:"intervals"`
	Context          map[string]interface{} `json:"context,omitempty"`

	QueryResult []TopNItem `json:"-"`
}

type TopNItem struct {
	Timestamp string                   `json:"timestamp"`
	Result    []map[string]interface{} `json:"result"`
}

func (q *QueryTopN) setup() { q.QueryType = "topN" }
func (q *QueryTopN) onResponse(content []byte) error {
	res := new([]TopNItem)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// Select Query
// ---------------------------------

type QuerySelect struct {
	QueryType   string                 `json:"queryType"`
	DataSource  string                 `json:"dataSource"`
	Intervals   []string               `json:"intervals"`
	Filter      *Filter                `json:"filter,omitempty"`
	Dimensions  []DimSpec              `json:"dimensions"`
	Metrics     []string               `json:"metrics"`
	Granularity Granlarity             `json:"granularity"`
	PagingSpec  map[string]interface{} `json:"pagingSpec,omitempty"`
	Context     map[string]interface{} `json:"context,omitempty"`

	QueryResult []SelectBlob `json:"-"`
}

// Select json blob from druid comes back as following:
// http://druid.io/docs/latest/querying/select-query.html
// the interesting results are in events blob which we
// call as 'SelectEvent'.
type SelectBlob struct {
        Timestamp string       `json:"timestamp"`
        Result    SelectResult `json:"result"`
}

type SelectResult struct {
        PagingIdentifiers map[string]int64 `json:"pagingIdentifiers"`
        Events            []SelectEvent    `json:"events"`
}

type SelectEvent struct {
        SegmentId string                 `json:"segmentId"`
        Offset    int64                  `json:"offset"`
        Event     map[string]interface{} `json:"event"`
}

func (q *QuerySelect) setup() { q.QueryType = "select" }
func (q *QuerySelect) onResponse(content []byte) error {
	res := new([]SelectBlob)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}
<commit_msg>add support for descending clause in select queries<commit_after>package godruid

import (
	"encoding/json"
)

// Check http://druid.io/docs/0.6.154/Querying.html#query-operators for detail description.

// The Query interface stands for any kinds of druid query.
type Query interface {
	setup()
	onResponse(content []byte) error
}

// ---------------------------------
// GroupBy Query
// ---------------------------------

type QueryGroupBy struct {
	QueryType        string                 `json:"queryType"`
	DataSource       string                 `json:"dataSource"`
	Dimensions       []DimSpec              `json:"dimensions"`
	Granularity      Granlarity             `json:"granularity"`
	LimitSpec        *Limit                 `json:"limitSpec,omitempty"`
	Having           *Having                `json:"having,omitempty"`
	Filter           *Filter                `json:"filter,omitempty"`
	Aggregations     []Aggregation          `json:"aggregations"`
	PostAggregations []PostAggregation      `json:"postAggregations,omitempty"`
	Intervals        []string               `json:"intervals"`
	Context          map[string]interface{} `json:"context,omitempty"`

	QueryResult []GroupbyItem `json:"-"`
}

type GroupbyItem struct {
	Version   string                 `json:"version"`
	Timestamp string                 `json:"timestamp"`
	Event     map[string]interface{} `json:"event"`
}

func (q *QueryGroupBy) setup() { q.QueryType = "groupBy" }
func (q *QueryGroupBy) onResponse(content []byte) error {
	res := new([]GroupbyItem)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// Search Query
// ---------------------------------

type QuerySearch struct {
	QueryType        string                 `json:"queryType"`
	DataSource       string                 `json:"dataSource"`
	Granularity      Granlarity             `json:"granularity"`
	Filter           *Filter                `json:"filter,omitempty"`
	Intervals        []string               `json:"intervals"`
	SearchDimensions []string               `json:"searchDimensions,omitempty"`
	Query            *SearchQuery           `json:"query"`
	Sort             *SearchSort            `json:"sort"`
	Context          map[string]interface{} `json:"context,omitempty"`

	QueryResult []SearchItem `json:"-"`
}

type SearchItem struct {
	Timestamp string     `json:"timestamp"`
	Result    []DimValue `json:"result"`
}

type DimValue struct {
	Dimension string `json:"dimension"`
	Value     string `json:"value"`
}

func (q *QuerySearch) setup() { q.QueryType = "search" }
func (q *QuerySearch) onResponse(content []byte) error {
	res := new([]SearchItem)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// SegmentMetadata Query
// ---------------------------------

type QuerySegmentMetadata struct {
	QueryType  string                 `json:"queryType"`
	DataSource string                 `json:"dataSource"`
	Intervals  []string               `json:"intervals"`
	ToInclude  *ToInclude             `json:"toInclude,omitempty"`
	Merge      interface{}            `json:"merge,omitempty"`
	Context    map[string]interface{} `json:"context,omitempty"`

	QueryResult []SegmentMetaData `json:"-"`
}

type SegmentMetaData struct {
	Id        string                `json:"id"`
	Intervals []string              `json:"intervals"`
	Columns   map[string]ColumnItem `json:"columns"`
}

type ColumnItem struct {
	Type        string      `json:"type"`
	Size        int         `json:"size"`
	Cardinality interface{} `json:"cardinality"`
}

func (q *QuerySegmentMetadata) setup() { q.QueryType = "segmentMetadata" }
func (q *QuerySegmentMetadata) onResponse(content []byte) error {
	res := new([]SegmentMetaData)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// TimeBoundary Query
// ---------------------------------

type QueryTimeBoundary struct {
	QueryType  string                 `json:"queryType"`
	DataSource string                 `json:"dataSource"`
	Bound      string                 `json:"bound,omitempty"`
	Filter     *Filter                `json:"filter,omitempty"`
	Context    map[string]interface{} `json:"context,omitempty"`

	QueryResult []TimeBoundaryItem `json:"-"`
}

type TimeBoundaryItem struct {
	Timestamp string       `json:"timestamp"`
	Result    TimeBoundary `json:"result"`
}

type TimeBoundary struct {
	MinTime string `json:"minTime"`
	MaxTime string `json:"maxTime"`
}

func (q *QueryTimeBoundary) setup() { q.QueryType = "timeBoundary" }
func (q *QueryTimeBoundary) onResponse(content []byte) error {
	res := new([]TimeBoundaryItem)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// Timeseries Query
// ---------------------------------

type QueryTimeseries struct {
	QueryType        string                 `json:"queryType"`
	DataSource       string                 `json:"dataSource"`
	Granularity      Granlarity             `json:"granularity"`
	Filter           *Filter                `json:"filter,omitempty"`
	Aggregations     []Aggregation          `json:"aggregations"`
	PostAggregations []PostAggregation      `json:"postAggregations,omitempty"`
	Intervals        []string               `json:"intervals"`
	Context          map[string]interface{} `json:"context,omitempty"`

	QueryResult []Timeseries `json:"-"`
}

type Timeseries struct {
	Timestamp string                 `json:"timestamp"`
	Result    map[string]interface{} `json:"result"`
}

func (q *QueryTimeseries) setup() { q.QueryType = "timeseries" }
func (q *QueryTimeseries) onResponse(content []byte) error {
	res := new([]Timeseries)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// TopN Query
// ---------------------------------

type QueryTopN struct {
	QueryType        string                 `json:"queryType"`
	DataSource       string                 `json:"dataSource"`
	Granularity      Granlarity             `json:"granularity"`
	Dimension        DimSpec                `json:"dimension"`
	Threshold        int                    `json:"threshold"`
	Metric           *TopNMetric            `json:"metric"`
	Filter           *Filter                `json:"filter,omitempty"`
	Aggregations     []Aggregation          `json:"aggregations"`
	PostAggregations []PostAggregation      `json:"postAggregations,omitempty"`
	Intervals        []string               `json:"intervals"`
	Context          map[string]interface{} `json:"context,omitempty"`

	QueryResult []TopNItem `json:"-"`
}

type TopNItem struct {
	Timestamp string                   `json:"timestamp"`
	Result    []map[string]interface{} `json:"result"`
}

func (q *QueryTopN) setup() { q.QueryType = "topN" }
func (q *QueryTopN) onResponse(content []byte) error {
	res := new([]TopNItem)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}

// ---------------------------------
// Select Query
// ---------------------------------

type QuerySelect struct {
	QueryType   string                 `json:"queryType"`
	DataSource  string                 `json:"dataSource"`
	Intervals   []string               `json:"intervals"`
	Descending  bool                   `json:"descending"`
	Filter      *Filter                `json:"filter,omitempty"`
	Dimensions  []DimSpec              `json:"dimensions"`
	Metrics     []string               `json:"metrics"`
	Granularity Granlarity             `json:"granularity"`
	PagingSpec  map[string]interface{} `json:"pagingSpec,omitempty"`
	Context     map[string]interface{} `json:"context,omitempty"`

	QueryResult []SelectBlob `json:"-"`
}

// Select json blob from druid comes back as following:
// http://druid.io/docs/latest/querying/select-query.html
// the interesting results are in events blob which we
// call as 'SelectEvent'.
type SelectBlob struct {
	Timestamp string       `json:"timestamp"`
	Result    SelectResult `json:"result"`
}

type SelectResult struct {
	PagingIdentifiers map[string]int64 `json:"pagingIdentifiers"`
	Events            []SelectEvent    `json:"events"`
}

type SelectEvent struct {
	SegmentId string                 `json:"segmentId"`
	Offset    int64                  `json:"offset"`
	Event     map[string]interface{} `json:"event"`
}

func (q *QuerySelect) setup() { q.QueryType = "select" }
func (q *QuerySelect) onResponse(content []byte) error {
	res := new([]SelectBlob)
	err := json.Unmarshal(content, res)
	if err != nil {
		return err
	}
	q.QueryResult = *res
	return nil
}
<|endoftext|>


<commit_before>package proto

type Cluster struct {
	Id          string      `json:"id,omitempty"`
	Name        string      `json:"name,omitempty"`
	BucketId    string      `json:"bucketId,omitempty"`
	ObjectState string      `json:"objectState,omitempty"`
	TeamId      string      `json:"teamId,omitempty"`
	Members     *[]Node     `json:"members,omitempty"`
	Details     *Details    `json:"details,omitempty"`
	Properties  *[]Property `json:"properties,omitempty"`
}

type ClusterFilter struct {
	Name     string `json:"name,omitempty"`
	BucketId string `json:"bucketid,omitempty"`
	TeamId   string `json:"teamId,omitempty"`
}

//
func (c *Cluster) DeepCompare(a *Cluster) bool {
	if a == nil {
		return false
	}

	if c.Id != a.Id ||
		c.Name != a.Name ||
		c.BucketId != a.BucketId ||
		c.ObjectState != a.ObjectState ||
		c.TeamId != a.TeamId {
		return false
	}

member:
	for i, _ := range *c.Members {
		for j, _ := range *a.Members {
			if (*c.Members)[i].Id == (*a.Members)[j].Id {
				continue member
			}
		}
		return false
	}
	return true
}

func NewClusterRequest() Request {
	return Request{
		Flags:   &Flags{},
		Cluster: &Cluster{},
	}
}

func NewClusterFilter() Request {
	return Request{
		Filter: &Filter{
			Cluster: &ClusterFilter{},
		},
	}
}

func NewClusterResult() Result {
	return Result{
		Errors:   &[]string{},
		Clusters: &[]Cluster{},
	}
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Deepcompare: fix nilptr in Cluster.Members<commit_after>package proto

type Cluster struct {
	Id          string      `json:"id,omitempty"`
	Name        string      `json:"name,omitempty"`
	BucketId    string      `json:"bucketId,omitempty"`
	ObjectState string      `json:"objectState,omitempty"`
	TeamId      string      `json:"teamId,omitempty"`
	Members     *[]Node     `json:"members,omitempty"`
	Details     *Details    `json:"details,omitempty"`
	Properties  *[]Property `json:"properties,omitempty"`
}

type ClusterFilter struct {
	Name     string `json:"name,omitempty"`
	BucketId string `json:"bucketid,omitempty"`
	TeamId   string `json:"teamId,omitempty"`
}

//
func (c *Cluster) DeepCompare(a *Cluster) bool {
	if a == nil {
		return false
	}

	if c.Id != a.Id ||
		c.Name != a.Name ||
		c.BucketId != a.BucketId ||
		c.ObjectState != a.ObjectState ||
		c.TeamId != a.TeamId {
		return false
	}

	if c.Members != nil && a.Members != nil {
	member:
		for i, _ := range *c.Members {
			for j, _ := range *a.Members {
				if (*c.Members)[i].Id == (*a.Members)[j].Id {
					continue member
				}
			}
			return false
		}
		return true
	} else if c.Members != nil && a.Members == nil {
		return false
	} else if c.Members == nil && a.Members != nil {
		return false
	}
	return true
}

func NewClusterRequest() Request {
	return Request{
		Flags:   &Flags{},
		Cluster: &Cluster{},
	}
}

func NewClusterFilter() Request {
	return Request{
		Filter: &Filter{
			Cluster: &ClusterFilter{},
		},
	}
}

func NewClusterResult() Result {
	return Result{
		Errors:   &[]string{},
		Clusters: &[]Cluster{},
	}
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package riak

// Cluster states

const (
	CLUSTER_ERROR state = iota
	CLUSTER_CREATED
	CLUSTER_RUNNING
	CLUSTER_QUEUING
	CLUSTER_SHUTTING_DOWN
	CLUSTER_SHUTDOWN
)

type ClusterOptions struct {
	Nodes       []*Node
	NodeManager NodeManager
}

type Cluster struct {
	nodes       []*Node
	nodeManager NodeManager
	stateData
}

var defaultClusterOptions = &ClusterOptions{
	Nodes:       make([]*Node, 0),
	NodeManager: &defaultNodeManager{},
}

func NewCluster(options *ClusterOptions) (c *Cluster, err error) {
	if options == nil {
		options = defaultClusterOptions
	}
	if options.NodeManager == nil {
		options.NodeManager = &defaultNodeManager{}
	}

	c = &Cluster{}

	if c.nodes, err = optNodes(options.Nodes); err != nil {
		c = nil
		return
	}

	c.nodeManager = options.NodeManager

	c.setStateDesc("CLUSTER_ERROR", "CLUSTER_CREATED", "CLUSTER_RUNNING", "CLUSTER_QUEUING", "CLUSTER_SHUTTING_DOWN", "CLUSTER_SHUTDOWN")
	c.setState(CLUSTER_CREATED)
	return
}

// exported funcs

func (c *Cluster) String() string {
	// return fmt.Sprintf("%v|%d", c.addr)
	return "TODO cluster"
}

func (c *Cluster) Start(options *ClusterOptions) (err error) {
	if c.isCurrentState(CLUSTER_RUNNING) {
		logWarnln("[Cluster] cluster already running.")
		return
	}
	if c.isCurrentState(CLUSTER_CREATED) {
		logDebug("[Cluster] starting.")

		for _, node := range c.nodes {
			if err = node.Start(); err != nil {
				return
			}
		}

		c.setState(CLUSTER_RUNNING)
		logDebug("[Cluster] cluster started.")
	}
	return
}

// non-exported funcs

func optNodes(nodes []*Node) (rv []*Node, err error) {
	if nodes == nil {
		nodes = make([]*Node, 0)
	}
	if len(nodes) == 0 {
		var defaultNode *Node
		if defaultNode, err = NewNode(nil); err == nil {
			rv = append(nodes, defaultNode)
		}
	} else {
		rv = nodes
	}
	return
}
<commit_msg>Add more function to cluster object<commit_after>package riak

import "errors"

// Cluster states

const (
	CLUSTER_ERROR state = iota
	CLUSTER_CREATED
	CLUSTER_RUNNING
	CLUSTER_QUEUEING
	CLUSTER_SHUTTING_DOWN
	CLUSTER_SHUTDOWN
)

type ClusterOptions struct {
	Nodes       []*Node
	NodeManager NodeManager
}

type Cluster struct {
	nodes       []*Node
	nodeManager NodeManager
	stateData
}

var defaultClusterOptions = &ClusterOptions{
	Nodes:       make([]*Node, 0),
	NodeManager: &defaultNodeManager{},
}

func NewCluster(options *ClusterOptions) (c *Cluster, err error) {
	if options == nil {
		options = defaultClusterOptions
	}
	if options.NodeManager == nil {
		options.NodeManager = &defaultNodeManager{}
	}

	c = &Cluster{}

	if c.nodes, err = optNodes(options.Nodes); err != nil {
		c = nil
		return
	}

	c.nodeManager = options.NodeManager

	c.setStateDesc("CLUSTER_ERROR", "CLUSTER_CREATED", "CLUSTER_RUNNING", "CLUSTER_QUEUEING", "CLUSTER_SHUTTING_DOWN", "CLUSTER_SHUTDOWN")
	c.setState(CLUSTER_CREATED)
	return
}

// exported funcs

func (c *Cluster) String() string {
	// return fmt.Sprintf("%v|%d", c.addr)
	return "TODO cluster"
}

func (c *Cluster) Start() (err error) {
	if c.isCurrentState(CLUSTER_RUNNING) {
		logWarnln("[Cluster] cluster already running.")
		return
	}
	if err = c.stateCheck(CLUSTER_CREATED); err != nil {
		return
	} else {
		logDebug("[Cluster] starting.")

		for _, node := range c.nodes {
			if err = node.Start(); err != nil {
				return
			}
		}

		c.setState(CLUSTER_RUNNING)
		logDebug("[Cluster] cluster started.")
	}
	return
}

func (c *Cluster) Stop() (err error) {
	if err = c.stateCheck(CLUSTER_RUNNING, CLUSTER_QUEUEING); err != nil {
		return
	} else {
		logDebug("[Cluster] shutting down")
		c.setState(CLUSTER_SHUTTING_DOWN)
		for _, node := range c.nodes {
			err = node.Stop() // TODO multiple errors?
		}

		allStopped := true
		logDebug("[Cluster] checking to see if nodes are shut down")
		for _, node := range c.nodes {
			nodeState := node.getState()
			if nodeState != NODE_SHUTDOWN {
				allStopped = false
				break
			}
		}

		if allStopped {
			c.setState(CLUSTER_SHUTDOWN)
			logDebug("[Cluster] cluster shut down")
			/* TODO
			if (this._commandQueue.length) {
				logger.warn('[RiakCluster] There were %d commands in the queue at shutdown',
					this._commandQueue.length);
			}
			*/
		} else {
			// TODO is this even possible?
			logDebug("[Cluster] nodes still running")
			/*
			var self = this;
			setTimeout(function() {
				self._shutdown();
			}, 1000);
			*/
		}
	}
	return
}

func (c *Cluster) Execute(command Command) (err error) {
	// TODO retries
	// TODO command queueing
	// TODO "previous" node
	executed := false
	if executed, err = c.nodeManager.ExecuteOnNode(c.nodes, command, nil); err != nil {
		return
	}

    if (!executed) {
		err = errors.New("No nodes available to execute command.")
    }

	return
}

// non-exported funcs

func optNodes(nodes []*Node) (rv []*Node, err error) {
	if nodes == nil {
		nodes = make([]*Node, 0)
	}
	if len(nodes) == 0 {
		var defaultNode *Node
		if defaultNode, err = NewNode(nil); err == nil {
			rv = append(nodes, defaultNode)
		}
	} else {
		rv = nodes
	}
	return
}
<|endoftext|>