<commit_before>package workflow_test

import (
	"errors"
	"fmt"
	"github.com/stretchr/testify/assert"
	"github.com/viant/endly"
	"github.com/viant/endly/testing/endpoint/http"
	"github.com/viant/toolbox"
	"github.com/viant/toolbox/url"
	"path"
	"strings"
	"testing"

	_ "github.com/mattn/go-sqlite3"
	_ "github.com/viant/endly/cli"

	_ "github.com/viant/endly/cloud/ec2"
	_ "github.com/viant/endly/cloud/gce"
	_ "github.com/viant/endly/testing/endpoint/http"

	_ "github.com/viant/endly/testing/dsunit"
	_ "github.com/viant/endly/testing/log"
	_ "github.com/viant/endly/testing/validator"

	_ "github.com/viant/endly/testing/runner/http"
	_ "github.com/viant/endly/testing/runner/selenium"

	_ "github.com/viant/endly/deployment/build"
	_ "github.com/viant/endly/deployment/deploy"
	_ "github.com/viant/endly/deployment/sdk"
	_ "github.com/viant/endly/deployment/vc"

	_ "github.com/viant/endly/system/daemon"
	_ "github.com/viant/endly/system/docker"
	_ "github.com/viant/endly/system/exec"
	_ "github.com/viant/endly/system/process"
	_ "github.com/viant/endly/system/storage"
	_ "github.com/viant/toolbox/storage"
	_ "github.com/viant/toolbox/storage/scp"

	_ "github.com/viant/endly/static"

	"github.com/viant/endly/model"
	"github.com/viant/endly/workflow"
)

func getServiceWithWorkflow(workflowURI string) (endly.Manager, endly.Service, error) {
	manager := endly.New()
	service, err := manager.Service(workflow.ServiceID)
	if err == nil {
		context := manager.NewContext(toolbox.NewContext())
		response := service.Run(context, &workflow.LoadRequest{
			Source: url.NewResource(workflowURI),
		})
		if response.Error != "" {
			return nil, nil, errors.New(response.Error)
		}

	}
	return manager, service, err
}

func getServiceWithWorkflowContext(workflowURI string) (*endly.Context, endly.Service, error) {
	manager := endly.New()
	service, err := manager.Service(workflow.ServiceID)
	context := manager.NewContext(toolbox.NewContext())

	if err == nil {
		response := service.Run(context, &workflow.LoadRequest{
			Source: url.NewResource(workflowURI),
		})
		if response.Error != "" {
			return nil, nil, errors.New(response.Error)
		}
		if workflowLoadResponse, ok := response.Response.(*workflow.LoadResponse); ok {
			workflow.Push(context, model.NewProcess(workflowLoadResponse.Workflow.Source, workflowLoadResponse.Workflow, nil))
		} else {
			fmt.Printf("unexpected response: %T\n", response.Response)
		}
	}
	return context, service, err
}

func TestWorkflowService_SwitchAction(t *testing.T) {
	context, service, err := getServiceWithWorkflowContext("test/nop/workflow.csv")
	assert.Nil(t, err)

	request := &workflow.SwitchRequest{
		SourceKey: "run",
		Cases: []*workflow.SwitchCase{
			{
				Value: "action1",
				ServiceRequest: &model.ServiceRequest{
					Service: "nop",
					Action:  "nop",
					Request: map[string]interface{}{
						"In": map[string]interface{}{"r": "test 1"},
					},
				},
			},
			{
				Value: "action2",
				ServiceRequest: &model.ServiceRequest{
					Service: "nop",
					Action:  "nop",
					Request: map[string]interface{}{
						"In": map[string]interface{}{"r": "test 2"},
					},
				},
			},
		},
		Default: &workflow.SwitchCase{
			ServiceRequest: &model.ServiceRequest{
				Service: "nop",
				Action:  "nop",
				Request: map[string]interface{}{
					"In": map[string]interface{}{"r": "test 3"},
				},
			},
		},
	}

	var state = context.State()

	type useCase struct {
		SourceKey string
		Expected  interface{}
	}

	for _, testCase := range []useCase{
		{
			SourceKey: "action1",
			Expected:  "test 1",
		},
		{
			SourceKey: "action2",
			Expected:  "test 2",
		},
		{
			SourceKey: "unknown",
			Expected:  "test 3",
		},
	} {
		state.Put("run", testCase.SourceKey)
		serviceResponse := service.Run(context, request)
		assert.EqualValues(t, "", serviceResponse.Error)
		response := toolbox.AsMap(serviceResponse.Response)
		assert.EqualValues(t, testCase.Expected, response["r"])
	}

}

func TestWorkflowService_RunDsUnitWorkflow(t *testing.T) {

	manager, service, err := getServiceWithWorkflow("test/dsunit/workflow.csv")
	if assert.Nil(t, err) {

		{
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks: "prepare",
				Name:  "workflow",
				Params: map[string]interface{}{
					"param1": 1,
				},
				EnableLogging: true,
				LogDirectory:  "logs",
			})

			if !assert.NotNil(t, serviceResponse) {
				return
			}

			assert.Equal(t, "", serviceResponse.Error)
			response, ok := serviceResponse.Response.(*workflow.RunResponse)

			if assert.True(t, ok) {
				if assert.NotNil(t, response) {
					if assert.True(t, len(response.Data) > 0) {
						return
					}

					dsUnit, ok := response.Data["dsunit"]
					if !ok {
						assert.Fail(t, fmt.Sprintf("expected dsunit key dsunit: %v", response.Data))
						return
					}
					var dsunit = toolbox.AsMap(dsUnit)
					var records = toolbox.AsSlice(dsunit["USER_ACCOUNT"])
					assert.EqualValues(t, 3, len(records))

				}

			}
		}

		{
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks: "*",

				Name: "workflow",

				Params: map[string]interface{}{
					"param1": 1,
				},
				EnableLogging: true,
				LogDirectory:  "/tmp/logs",
			})
			assert.Equal(t, "", serviceResponse.Error)

			response, ok := serviceResponse.Response.(*workflow.RunResponse)
			assert.True(t, ok)
			assert.NotNil(t, response)
			var dsunit = toolbox.AsMap(response.Data["dsunit"])
			var records = toolbox.AsSlice(dsunit["USER_ACCOUNT"])
			assert.EqualValues(t, 0, len(records)) //validate task shift elements from USER_ACCCOUNT array.

		}
	}
}

func TestWorkflowService_OnErrorTask(t *testing.T) {

	manager, service, _ := getServiceWithWorkflow("test/recover/workflow.csv")

	context := manager.NewContext(toolbox.NewContext())
	serviceResponse := service.Run(context, &workflow.RunRequest{
		Tasks:         "fail",
		Name:          "recover",
		Params:        map[string]interface{}{},
		EnableLogging: true,
		LogDirectory:  "logs",
	})

	assert.EqualValues(t, "", serviceResponse.Error)
	response, ok := serviceResponse.Response.(*workflow.RunResponse)
	if assert.True(t, ok) {
		errorCaught := toolbox.AsString(response.Data["errorCaught"])
		assert.True(t, strings.Contains(errorCaught, "this is test error "))
	}
}

func TestWorkflowService_RunHttpWorkflow(t *testing.T) {

	baseDir := toolbox.CallerDirectory(3)
	err := http.StartServer(8313, &http.HTTPServerTrips{
		IndexKeys:     []string{http.MethodKey, http.URLKey, http.BodyKey, http.CookieKey, http.ContentTypeKey},
		BaseDirectory: path.Join(baseDir, "test/endpoint"),
	})

	if !assert.Nil(t, err) {
		return
	}

	manager, service, err := getServiceWithWorkflow("test/http/workflow.csv")
	if assert.Nil(t, err) {

		context := manager.NewContext(toolbox.NewContext())
		serviceResponse := service.Run(context, &workflow.RunRequest{
			Tasks: "*",

			Name: "http_workflow",

			Params: map[string]interface{}{
				"appServer": "http://127.0.0.1:8313",
			},
			EnableLogging:     true,
			LogDirectory:      "logs",
			PublishParameters: true,
		})
		assert.EqualValues(t, "", serviceResponse.Error)
		response, ok := serviceResponse.Response.(*workflow.RunResponse)
		if assert.True(t, ok) {

			responses, ok := response.Data["httpResponses"]
			if assert.True(t, ok) {
				httpResponses := toolbox.AsSlice(responses)
				assert.EqualValues(t, 3, len(httpResponses))
				for _, item := range httpResponses {
					httpResponse := toolbox.AsMap(item)
					assert.EqualValues(t, 200, httpResponse["Code"])
				}
			}
		}
	}
}

func TestWorkflowService_RunLifeCycle(t *testing.T) {

	manager, service, err := getServiceWithWorkflow("test/lifecycle/workflow.csv")
	if assert.Nil(t, err) {

		context := manager.NewContext(toolbox.NewContext())
		serviceResponse := service.Run(context, &workflow.RunRequest{
			Tasks: "*",

			Name: "lifecycle",

			Params: map[string]interface{}{
				"object": map[string]interface{}{
					"key1": 1,
					"key2": "abc",
				},
			},
			PublishParameters: true,
			EnableLogging:     true,
			LogDirectory:      "logs",
		})

		if assert.EqualValues(t, "", serviceResponse.Error) {
			response, ok := serviceResponse.Response.(*workflow.RunResponse)
			if assert.True(t, ok) {
				assert.EqualValues(t, 2, response.Data["testPassed"])
				var anArray = toolbox.AsSlice(response.Data["array"])
				assert.EqualValues(t, 2, anArray[0])
				assert.EqualValues(t, 3, response.Data["counter"])
				var anObject = toolbox.AsMap(response.Data["object"])
				assert.EqualValues(t, 1, anObject["key1"])
				assert.EqualValues(t, "200", anObject["shift"])
			}
		}
	}
}

func TestWorkflowService_RunBroken(t *testing.T) {

	{
		//unsupported action error

		manager, service, err := getServiceWithWorkflow("test/broken/broken2.csv")
		if assert.Nil(t, err) {
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks:             "*",
				Name:              "broken2",
				Params:            map[string]interface{}{},
				PublishParameters: true,
			})
			assert.EqualValues(t, true, strings.Contains(serviceResponse.Error, "unknown nop.aaa service action at workflow.run"), serviceResponse.Error)
		}
	}

	{
		//unsupported action error

		manager, service, err := getServiceWithWorkflow("test/broken/broken2.csv")
		if assert.Nil(t, err) {
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks:             "*",
				Name:              "broken2",
				Params:            map[string]interface{}{},
				PublishParameters: true,
			})
			assert.EqualValues(t, true, strings.Contains(serviceResponse.Error, "unknown nop.aaa service action at workflow.run"), serviceResponse.Error)
		}
	}

	{
		//unsupported service error

		manager, service, err := getServiceWithWorkflow("test/broken/broken3.csv")
		if assert.Nil(t, err) {
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks:             "*",
				Name:              "broken3",
				Params:            map[string]interface{}{},
				PublishParameters: true,
			})
			assert.EqualValues(t, true, strings.Contains(serviceResponse.Error, "failed to lookup service: 'aaa'"), serviceResponse.Error)
		}
	}

	{
		//calling invalid workflow

		manager, service, err := getServiceWithWorkflow("test/broken/broken4.csv")
		if assert.Nil(t, err) {
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks:             "*",
				Name:              "broken4",
				Params:            map[string]interface{}{},
				PublishParameters: true,
			})
			assert.EqualValues(t, true, strings.Contains(serviceResponse.Error, "unable to locate workflow"), serviceResponse.Error)
		}
	}
}

func Test_WorkflowSwitchRequest_Validate(t *testing.T) {
	{
		request := &workflow.SwitchRequest{}
		assert.NotNil(t, request.Validate())
	}
	{
		request := &workflow.SwitchRequest{
			SourceKey: "abc",
		}
		assert.NotNil(t, request.Validate())
	}
	{
		request := &workflow.SwitchRequest{
			SourceKey: "abc",
			Cases: []*workflow.SwitchCase{
				{},
			},
		}
		assert.NotNil(t, request.Validate())
	}
	{
		request := &workflow.SwitchRequest{
			SourceKey: "abc",
			Cases: []*workflow.SwitchCase{
				{
					Value: "123",
				},
			},
		}
		assert.Nil(t, request.Validate())
	}
}
<commit_msg>Adding unit test for PrintRequest fix<commit_after>package workflow_test

import (
	"errors"
	"fmt"
	"path"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/viant/endly"
	"github.com/viant/endly/testing/endpoint/http"
	"github.com/viant/toolbox"
	"github.com/viant/toolbox/url"

	_ "github.com/mattn/go-sqlite3"
	_ "github.com/viant/endly/cli"

	_ "github.com/viant/endly/cloud/ec2"
	_ "github.com/viant/endly/cloud/gce"
	_ "github.com/viant/endly/testing/endpoint/http"

	_ "github.com/viant/endly/testing/dsunit"
	_ "github.com/viant/endly/testing/log"
	_ "github.com/viant/endly/testing/validator"

	_ "github.com/viant/endly/testing/runner/http"
	_ "github.com/viant/endly/testing/runner/selenium"

	_ "github.com/viant/endly/deployment/build"
	_ "github.com/viant/endly/deployment/deploy"
	_ "github.com/viant/endly/deployment/sdk"
	_ "github.com/viant/endly/deployment/vc"

	_ "github.com/viant/endly/system/daemon"
	_ "github.com/viant/endly/system/docker"
	_ "github.com/viant/endly/system/exec"
	_ "github.com/viant/endly/system/process"
	_ "github.com/viant/endly/system/storage"
	_ "github.com/viant/toolbox/storage"
	_ "github.com/viant/toolbox/storage/scp"

	_ "github.com/viant/endly/static"

	"github.com/viant/endly/model"
	"github.com/viant/endly/workflow"
)

func getServiceWithWorkflow(workflowURI string) (endly.Manager, endly.Service, error) {
	manager := endly.New()
	service, err := manager.Service(workflow.ServiceID)
	if err == nil {
		context := manager.NewContext(toolbox.NewContext())
		response := service.Run(context, &workflow.LoadRequest{
			Source: url.NewResource(workflowURI),
		})
		if response.Error != "" {
			return nil, nil, errors.New(response.Error)
		}

	}
	return manager, service, err
}

func getServiceWithWorkflowContext(workflowURI string) (*endly.Context, endly.Service, error) {
	manager := endly.New()
	service, err := manager.Service(workflow.ServiceID)
	context := manager.NewContext(toolbox.NewContext())

	if err == nil {
		response := service.Run(context, &workflow.LoadRequest{
			Source: url.NewResource(workflowURI),
		})
		if response.Error != "" {
			return nil, nil, errors.New(response.Error)
		}
		if workflowLoadResponse, ok := response.Response.(*workflow.LoadResponse); ok {
			workflow.Push(context, model.NewProcess(workflowLoadResponse.Workflow.Source, workflowLoadResponse.Workflow, nil))
		} else {
			fmt.Printf("unexpected response: %T\n", response.Response)
		}
	}
	return context, service, err
}

func TestWorkflowService_SwitchAction(t *testing.T) {
	context, service, err := getServiceWithWorkflowContext("test/nop/workflow.csv")
	assert.Nil(t, err)

	request := &workflow.SwitchRequest{
		SourceKey: "run",
		Cases: []*workflow.SwitchCase{
			{
				Value: "action1",
				ServiceRequest: &model.ServiceRequest{
					Service: "nop",
					Action:  "nop",
					Request: map[string]interface{}{
						"In": map[string]interface{}{"r": "test 1"},
					},
				},
			},
			{
				Value: "action2",
				ServiceRequest: &model.ServiceRequest{
					Service: "nop",
					Action:  "nop",
					Request: map[string]interface{}{
						"In": map[string]interface{}{"r": "test 2"},
					},
				},
			},
		},
		Default: &workflow.SwitchCase{
			ServiceRequest: &model.ServiceRequest{
				Service: "nop",
				Action:  "nop",
				Request: map[string]interface{}{
					"In": map[string]interface{}{"r": "test 3"},
				},
			},
		},
	}

	var state = context.State()

	type useCase struct {
		SourceKey string
		Expected  interface{}
	}

	for _, testCase := range []useCase{
		{
			SourceKey: "action1",
			Expected:  "test 1",
		},
		{
			SourceKey: "action2",
			Expected:  "test 2",
		},
		{
			SourceKey: "unknown",
			Expected:  "test 3",
		},
	} {
		state.Put("run", testCase.SourceKey)
		serviceResponse := service.Run(context, request)
		assert.EqualValues(t, "", serviceResponse.Error)
		response := toolbox.AsMap(serviceResponse.Response)
		assert.EqualValues(t, testCase.Expected, response["r"])
	}

}

func TestWorkflowService_RunDsUnitWorkflow(t *testing.T) {

	manager, service, err := getServiceWithWorkflow("test/dsunit/workflow.csv")
	if assert.Nil(t, err) {

		{
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks: "prepare",
				Name:  "workflow",
				Params: map[string]interface{}{
					"param1": 1,
				},
				EnableLogging: true,
				LogDirectory:  "logs",
			})

			if !assert.NotNil(t, serviceResponse) {
				return
			}

			assert.Equal(t, "", serviceResponse.Error)
			response, ok := serviceResponse.Response.(*workflow.RunResponse)

			if assert.True(t, ok) {
				if assert.NotNil(t, response) {
					if assert.True(t, len(response.Data) > 0) {
						return
					}

					dsUnit, ok := response.Data["dsunit"]
					if !ok {
						assert.Fail(t, fmt.Sprintf("expected dsunit key dsunit: %v", response.Data))
						return
					}
					var dsunit = toolbox.AsMap(dsUnit)
					var records = toolbox.AsSlice(dsunit["USER_ACCOUNT"])
					assert.EqualValues(t, 3, len(records))

				}

			}
		}

		{
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks: "*",

				Name: "workflow",

				Params: map[string]interface{}{
					"param1": 1,
				},
				EnableLogging: true,
				LogDirectory:  "/tmp/logs",
			})
			assert.Equal(t, "", serviceResponse.Error)

			response, ok := serviceResponse.Response.(*workflow.RunResponse)
			assert.True(t, ok)
			assert.NotNil(t, response)
			var dsunit = toolbox.AsMap(response.Data["dsunit"])
			var records = toolbox.AsSlice(dsunit["USER_ACCOUNT"])
			assert.EqualValues(t, 0, len(records)) //validate task shift elements from USER_ACCCOUNT array.

		}
	}
}

func TestWorkflowService_OnErrorTask(t *testing.T) {

	manager, service, _ := getServiceWithWorkflow("test/recover/workflow.csv")

	context := manager.NewContext(toolbox.NewContext())
	serviceResponse := service.Run(context, &workflow.RunRequest{
		Tasks:         "fail",
		Name:          "recover",
		Params:        map[string]interface{}{},
		EnableLogging: true,
		LogDirectory:  "logs",
	})

	assert.EqualValues(t, "", serviceResponse.Error)
	response, ok := serviceResponse.Response.(*workflow.RunResponse)
	if assert.True(t, ok) {
		errorCaught := toolbox.AsString(response.Data["errorCaught"])
		assert.True(t, strings.Contains(errorCaught, "this is test error "))
	}
}

func TestWorkflowService_RunHttpWorkflow(t *testing.T) {

	baseDir := toolbox.CallerDirectory(3)
	err := http.StartServer(8313, &http.HTTPServerTrips{
		IndexKeys:     []string{http.MethodKey, http.URLKey, http.BodyKey, http.CookieKey, http.ContentTypeKey},
		BaseDirectory: path.Join(baseDir, "test/endpoint"),
	})

	if !assert.Nil(t, err) {
		return
	}

	manager, service, err := getServiceWithWorkflow("test/http/workflow.csv")
	if assert.Nil(t, err) {

		context := manager.NewContext(toolbox.NewContext())
		serviceResponse := service.Run(context, &workflow.RunRequest{
			Tasks: "*",

			Name: "http_workflow",

			Params: map[string]interface{}{
				"appServer": "http://127.0.0.1:8313",
			},
			EnableLogging:     true,
			LogDirectory:      "logs",
			PublishParameters: true,
		})
		assert.EqualValues(t, "", serviceResponse.Error)
		response, ok := serviceResponse.Response.(*workflow.RunResponse)
		if assert.True(t, ok) {

			responses, ok := response.Data["httpResponses"]
			if assert.True(t, ok) {
				httpResponses := toolbox.AsSlice(responses)
				assert.EqualValues(t, 3, len(httpResponses))
				for _, item := range httpResponses {
					httpResponse := toolbox.AsMap(item)
					assert.EqualValues(t, 200, httpResponse["Code"])
				}
			}
		}
	}
}

func TestWorkflowService_RunLifeCycle(t *testing.T) {

	manager, service, err := getServiceWithWorkflow("test/lifecycle/workflow.csv")
	if assert.Nil(t, err) {

		context := manager.NewContext(toolbox.NewContext())
		serviceResponse := service.Run(context, &workflow.RunRequest{
			Tasks: "*",

			Name: "lifecycle",

			Params: map[string]interface{}{
				"object": map[string]interface{}{
					"key1": 1,
					"key2": "abc",
				},
			},
			PublishParameters: true,
			EnableLogging:     true,
			LogDirectory:      "logs",
		})

		if assert.EqualValues(t, "", serviceResponse.Error) {
			response, ok := serviceResponse.Response.(*workflow.RunResponse)
			if assert.True(t, ok) {
				assert.EqualValues(t, 2, response.Data["testPassed"])
				var anArray = toolbox.AsSlice(response.Data["array"])
				assert.EqualValues(t, 2, anArray[0])
				assert.EqualValues(t, 3, response.Data["counter"])
				var anObject = toolbox.AsMap(response.Data["object"])
				assert.EqualValues(t, 1, anObject["key1"])
				assert.EqualValues(t, "200", anObject["shift"])
			}
		}
	}
}

func TestWorkflowService_RunBroken(t *testing.T) {

	{
		//unsupported action error

		manager, service, err := getServiceWithWorkflow("test/broken/broken2.csv")
		if assert.Nil(t, err) {
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks:             "*",
				Name:              "broken2",
				Params:            map[string]interface{}{},
				PublishParameters: true,
			})
			assert.EqualValues(t, true, strings.Contains(serviceResponse.Error, "unknown nop.aaa service action at workflow.run"), serviceResponse.Error)
		}
	}

	{
		//unsupported action error

		manager, service, err := getServiceWithWorkflow("test/broken/broken2.csv")
		if assert.Nil(t, err) {
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks:             "*",
				Name:              "broken2",
				Params:            map[string]interface{}{},
				PublishParameters: true,
			})
			assert.EqualValues(t, true, strings.Contains(serviceResponse.Error, "unknown nop.aaa service action at workflow.run"), serviceResponse.Error)
		}
	}

	{
		//unsupported service error

		manager, service, err := getServiceWithWorkflow("test/broken/broken3.csv")
		if assert.Nil(t, err) {
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks:             "*",
				Name:              "broken3",
				Params:            map[string]interface{}{},
				PublishParameters: true,
			})
			assert.EqualValues(t, true, strings.Contains(serviceResponse.Error, "failed to lookup service: 'aaa'"), serviceResponse.Error)
		}
	}

	{
		//calling invalid workflow

		manager, service, err := getServiceWithWorkflow("test/broken/broken4.csv")
		if assert.Nil(t, err) {
			context := manager.NewContext(toolbox.NewContext())
			serviceResponse := service.Run(context, &workflow.RunRequest{
				Tasks:             "*",
				Name:              "broken4",
				Params:            map[string]interface{}{},
				PublishParameters: true,
			})
			assert.EqualValues(t, true, strings.Contains(serviceResponse.Error, "unable to locate workflow"), serviceResponse.Error)
		}
	}
}

func Test_WorkflowSwitchRequest_Validate(t *testing.T) {
	{
		request := &workflow.SwitchRequest{}
		assert.NotNil(t, request.Validate())
	}
	{
		request := &workflow.SwitchRequest{
			SourceKey: "abc",
		}
		assert.NotNil(t, request.Validate())
	}
	{
		request := &workflow.SwitchRequest{
			SourceKey: "abc",
			Cases: []*workflow.SwitchCase{
				{},
			},
		}
		assert.NotNil(t, request.Validate())
	}
	{
		request := &workflow.SwitchRequest{
			SourceKey: "abc",
			Cases: []*workflow.SwitchCase{
				{
					Value: "123",
				},
			},
		}
		assert.Nil(t, request.Validate())
	}
}

func Test_PrintRequest(t *testing.T) {

	t.Run("Case to check if error message is created", func(t *testing.T) {
		msg := "Test Error message"

		r := workflow.PrintRequest{
			Error: msg,
		}

		m := r.Messages()
		assert.Equal(t, 1, len(m))
		assert.Equal(t, msg, m[0].Items[0].Text)
	})

	t.Run("Case to check if regular message is created", func(t *testing.T) {
		msg := "Test regular message"

		r := workflow.PrintRequest{
			Message: msg,
		}

		m := r.Messages()
		assert.Equal(t, 1, len(m))
		assert.Equal(t, msg, m[0].Items[0].Text)
	})
}
<|endoftext|>


<commit_before>package endly

import (
	"fmt"
	"github.com/viant/toolbox"
	"strings"
)

//FailedTest represents a failed test
type FailedTest struct {
	PathIndex int
	Path      string
	Expected  interface{}
	Actual    interface{}
	Message   string
}

//ExtractPathIndex extract index  from path
func ExtractPathIndex(path string) (int, string) {
	startPathPosition := strings.Index(path, "]")
	if startPathPosition == -1 || startPathPosition > 20 {

		return -1, path
	}
	pathSegments := strings.Split(path, "]")
	if len(pathSegments) == 0 {
		return -1, path
	}
	indexSegment := pathSegments[0]
	endPositionOfTheFirstPathSegment := len(indexSegment) + 1
	startPathPosition = strings.LastIndex(indexSegment, "[")
	if startPathPosition == -1 {
		return -1, path
	}
	var candidate = string(indexSegment[startPathPosition+1:])
	var index = toolbox.AsInt(candidate)
	if index > 0 || strings.Contains(candidate, toolbox.AsString(index)) {
		if len(path) == endPositionOfTheFirstPathSegment-1 {
			return index, ""
		}
		return index, string(path[endPositionOfTheFirstPathSegment:])
	}
	return -1, path
}

//NewFailedTest creates a new FailedTest instance
func NewFailedTest(path, message string, expected, actual interface{}) *FailedTest {
	var result = &FailedTest{
		Message:  message,
		Expected: expected,
		Actual:   actual,
	}
	result.PathIndex, result.Path = ExtractPathIndex(path)

	return result
}

//ValidationInfo represents assertion info
type ValidationInfo struct {
	Description string
	TagId       string
	TestPassed  int
	FailedTests []*FailedTest
}

//AddFailure appends failure
func (ar *ValidationInfo) AddFailure(failedTest *FailedTest) {
	if len(ar.FailedTests) == 0 {
		ar.FailedTests = make([]*FailedTest, 0)
	}
	ar.FailedTests = append(ar.FailedTests, failedTest)
}

//HasFailure returns true if at least one failure has been registered
func (ar *ValidationInfo) HasFailure() bool {
	return len(ar.FailedTests) > 0
}

//Message provides summary message
func (ar *ValidationInfo) Message() string {

	var failed = make([]string, 0)

	for i := 0; i < len(ar.FailedTests); i++ {
		failed = append(failed, ar.FailedTests[i].Message)
	}

	return fmt.Sprintf("Passed: %v\nFailed:%v\n-----\n\t%v\n",
		ar.TestPassed,
		len(ar.FailedTests),
		strings.Join(failed, "\n\t"),
	)
}
<commit_msg>added fialedtest count<commit_after>package endly

import (
	"fmt"
	"github.com/viant/toolbox"
	"strings"
)

//FailedTest represents a failed test
type FailedTest struct {
	PathIndex int
	Path      string
	Expected  interface{}
	Actual    interface{}
	Message   string
}

//ExtractPathIndex extract index  from path
func ExtractPathIndex(path string) (int, string) {
	startPathPosition := strings.Index(path, "]")
	if startPathPosition == -1 || startPathPosition > 20 {

		return -1, path
	}
	pathSegments := strings.Split(path, "]")
	if len(pathSegments) == 0 {
		return -1, path
	}
	indexSegment := pathSegments[0]
	endPositionOfTheFirstPathSegment := len(indexSegment) + 1
	startPathPosition = strings.LastIndex(indexSegment, "[")
	if startPathPosition == -1 {
		return -1, path
	}
	var candidate = string(indexSegment[startPathPosition+1:])
	var index = toolbox.AsInt(candidate)
	if index > 0 || strings.Contains(candidate, toolbox.AsString(index)) {
		if len(path) == endPositionOfTheFirstPathSegment-1 {
			return index, ""
		}
		return index, string(path[endPositionOfTheFirstPathSegment:])
	}
	return -1, path
}

//NewFailedTest creates a new FailedTest instance
func NewFailedTest(path, message string, expected, actual interface{}) *FailedTest {
	var result = &FailedTest{
		Message:  message,
		Expected: expected,
		Actual:   actual,
	}
	result.PathIndex, result.Path = ExtractPathIndex(path)

	return result
}

//ValidationInfo represents assertion info
type ValidationInfo struct {
	Description string
	TagId       string
	TestPassed  int
	FailedTests []*FailedTest
	TestFailed int
}

//AddFailure appends failure
func (ar *ValidationInfo) AddFailure(failedTest *FailedTest) {
	if len(ar.FailedTests) == 0 {
		ar.FailedTests = make([]*FailedTest, 0)
	}
	ar.FailedTests = append(ar.FailedTests, failedTest)
	ar.TestFailed++
}

//HasFailure returns true if at least one failure has been registered
func (ar *ValidationInfo) HasFailure() bool {
	return len(ar.FailedTests) > 0
}

//Message provides summary message
func (ar *ValidationInfo) Message() string {

	var failed = make([]string, 0)

	for i := 0; i < len(ar.FailedTests); i++ {
		failed = append(failed, ar.FailedTests[i].Message)
	}

	return fmt.Sprintf("Passed: %v\nFailed:%v\n-----\n\t%v\n",
		ar.TestPassed,
		len(ar.FailedTests),
		strings.Join(failed, "\n\t"),
	)
}
<|endoftext|>


<commit_before>package core

import (
	"bufio"
	"io"
	"strconv"
	"strings"
)

type Tag struct {
	Code  int
	Value DataType
}

var noneString, _ = NewString("NONE")
var NoneTag Tag = Tag{999999, noneString}

type DataTypeFactory func(string) (DataType, error)

var GroupCodeTypes map[int]DataTypeFactory

type NextTagFunction func() (*Tag, error)

func Tagger(stream io.Reader) NextTagFunction {
	counter := 0
	scanner := bufio.NewScanner(stream)

	readLine := func() (string, error) {
		if scanner.Scan() {
			return scanner.Text(), nil
		} else if err := scanner.Err(); err != nil {
			return "", err
		}

		return "", nil
	}

	return func() (*Tag, error) {
		code, err := readLine()
		if err != nil {
			return &NoneTag, err
		}
		value, err := readLine()
		if err != nil {
			return &NoneTag, err
		}

		charsToTrim := " \r\n"
		counter += 2
		if len(code) > 0 && len(value) > 0 {
			intCode, err := strconv.Atoi(strings.Trim(code, charsToTrim))
			if err != nil {
				return &NoneTag, err
			}
			valueType, _ := GroupCodeTypes[intCode](strings.Trim(value, charsToTrim))
			tag := new(Tag)
			tag.Code = intCode
			tag.Value = valueType
			return tag, nil
		}

		// EOF
		return &NoneTag, nil
	}
}

func init() {
	GroupCodeTypes = make(map[int]DataTypeFactory)

	for code := 0; code < 10; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 10; code < 20; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 20; code < 60; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 60; code < 100; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 100; code < 106; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 110; code < 113; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 113; code < 150; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 170; code < 180; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	GroupCodeTypes[210] = NewFloat

	for code := 211; code < 240; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 270; code < 290; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 290; code < 300; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 300; code < 370; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 370; code < 390; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 390; code < 400; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 400; code < 410; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 410; code < 420; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 420; code < 430; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 430; code < 440; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 440; code < 460; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 460; code < 470; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 470; code < 480; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 480; code < 482; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 999; code < 1010; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 1010; code < 1020; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 1020; code < 1060; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 1060; code < 1072; code++ {
		GroupCodeTypes[code] = NewInteger
	}
}
<commit_msg>Documentation for tags module.<commit_after>package core

import (
	"bufio"
	"io"
	"strconv"
	"strings"
)

// Tag from a DXF file.
type Tag struct {
	Code  int
	Value DataType
}

// NoneTag a constant that represents a nul tag.
var NoneTag = Tag{999999, &String{"NONE"}}

// DataTypeFactory a factory function that receives a string and return an instance
// of a DataType. The string should contain the DataType value.
type DataTypeFactory func(string) (DataType, error)

// GroupCodeTypes maps DXF group codes to DataTypeFactory functions. See the init
// functions for the known group codes.
var GroupCodeTypes map[int]DataTypeFactory

// NextTagFunction is the prototype of a function that returns the next Tag in a stream.
type NextTagFunction func() (*Tag, error)

// Tagger function. Returns a NextTagFunction that, in turn, returns the tags
// from the stream sequentially each time it is called. It finishes when it returns
// an error or a NoneTag.
func Tagger(stream io.Reader) NextTagFunction {
	counter := 0
	scanner := bufio.NewScanner(stream)

	readLine := func() (string, error) {
		if scanner.Scan() {
			return scanner.Text(), nil
		} else if err := scanner.Err(); err != nil {
			return "", err
		}

		return "", nil
	}

	return func() (*Tag, error) {
		code, err := readLine()
		if err != nil {
			return &NoneTag, err
		}
		value, err := readLine()
		if err != nil {
			return &NoneTag, err
		}

		charsToTrim := " \r\n"
		counter += 2
		if len(code) > 0 && len(value) > 0 {
			intCode, err := strconv.Atoi(strings.Trim(code, charsToTrim))
			if err != nil {
				return &NoneTag, err
			}
			valueType, _ := GroupCodeTypes[intCode](strings.Trim(value, charsToTrim))
			tag := new(Tag)
			tag.Code = intCode
			tag.Value = valueType
			return tag, nil
		}

		// EOF
		return &NoneTag, nil
	}
}

func init() {
	GroupCodeTypes = make(map[int]DataTypeFactory)

	for code := 0; code < 10; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 10; code < 20; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 20; code < 60; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 60; code < 100; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 100; code < 106; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 110; code < 113; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 113; code < 150; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 170; code < 180; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	GroupCodeTypes[210] = NewFloat

	for code := 211; code < 240; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 270; code < 290; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 290; code < 300; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 300; code < 370; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 370; code < 390; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 390; code < 400; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 400; code < 410; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 410; code < 420; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 420; code < 430; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 430; code < 440; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 440; code < 460; code++ {
		GroupCodeTypes[code] = NewInteger
	}

	for code := 460; code < 470; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 470; code < 480; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 480; code < 482; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 999; code < 1010; code++ {
		GroupCodeTypes[code] = NewString
	}

	for code := 1010; code < 1020; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 1020; code < 1060; code++ {
		GroupCodeTypes[code] = NewFloat
	}

	for code := 1060; code < 1072; code++ {
		GroupCodeTypes[code] = NewInteger
	}
}
<|endoftext|>


<commit_before>package blinkstick

import (
	"fmt"
	"image/color"

	"github.com/boombuler/hid"
)

// Version of Blinkstick
// One Line for this, used by release.sh script
// Keep "const Version on one line"
const Version = "0.0.14"

// VendorID blinkstick
const VendorID = 0x20a0

// ProductID blinkstick
const ProductID = 0x41e5

// USBDevice ...
type USBDevice struct {
	DeviceInfo *hid.DeviceInfo
	Device     *hid.Device
}

// Blinkstick represents a blinkstick device
type Blinkstick interface {
	List() []Blinkstick
	SetColor(color.Color) error
	GetDeviceInfo() *hid.DeviceInfo
	ListFilter(hid *hid.DeviceInfo) (bool, Blinkstick)
}

// SetColor set color
func (usbDevice *USBDevice) setColor(index byte, c color.Color) error {
	if usbDevice.Device == nil {
		if err := usbDevice.Open(); err != nil {
			return err
		}
	}
	r, g, b, _ := c.RGBA()
	d := *usbDevice.Device
	return d.WriteFeature([]byte{0x05, 0x00, index, byte(r >> 8), byte(g >> 8), byte(b >> 8)})
}

// Open open a device
func (usbDevice *USBDevice) Open() error {
	device, err := usbDevice.DeviceInfo.Open()
	if err != nil {
		return fmt.Errorf("Error while opening device: %s", err)
	}
	usbDevice.Device = &device
	return nil
}

// ListFilter is used to filter device on List
type ListFilter func(*hid.DeviceInfo) (bool, Blinkstick)

// List gets all blinkstick device
func List(opts ...ListFilter) []Blinkstick {
	out := []Blinkstick{}

	if len(opts) == 0 {
		opts = append(opts, Nano{}.ListFilter)
	}

	for di := range hid.Devices() {
		if di.VendorId == VendorID && di.ProductId == ProductID {
			for _, o := range opts {
				if toKeep, blinkstick := o(di); toKeep {
					out = append(out, blinkstick)
				}
			}

		}
	}
	return out
}
<commit_msg>[auto] bump version to v0.0.15<commit_after>package blinkstick

import (
	"fmt"
	"image/color"

	"github.com/boombuler/hid"
)

// Version of Blinkstick
// One Line for this, used by release.sh script
// Keep "const Version on one line"
const Version = "0.0.15"

// VendorID blinkstick
const VendorID = 0x20a0

// ProductID blinkstick
const ProductID = 0x41e5

// USBDevice ...
type USBDevice struct {
	DeviceInfo *hid.DeviceInfo
	Device     *hid.Device
}

// Blinkstick represents a blinkstick device
type Blinkstick interface {
	List() []Blinkstick
	SetColor(color.Color) error
	GetDeviceInfo() *hid.DeviceInfo
	ListFilter(hid *hid.DeviceInfo) (bool, Blinkstick)
}

// SetColor set color
func (usbDevice *USBDevice) setColor(index byte, c color.Color) error {
	if usbDevice.Device == nil {
		if err := usbDevice.Open(); err != nil {
			return err
		}
	}
	r, g, b, _ := c.RGBA()
	d := *usbDevice.Device
	return d.WriteFeature([]byte{0x05, 0x00, index, byte(r >> 8), byte(g >> 8), byte(b >> 8)})
}

// Open open a device
func (usbDevice *USBDevice) Open() error {
	device, err := usbDevice.DeviceInfo.Open()
	if err != nil {
		return fmt.Errorf("Error while opening device: %s", err)
	}
	usbDevice.Device = &device
	return nil
}

// ListFilter is used to filter device on List
type ListFilter func(*hid.DeviceInfo) (bool, Blinkstick)

// List gets all blinkstick device
func List(opts ...ListFilter) []Blinkstick {
	out := []Blinkstick{}

	if len(opts) == 0 {
		opts = append(opts, Nano{}.ListFilter)
	}

	for di := range hid.Devices() {
		if di.VendorId == VendorID && di.ProductId == ProductID {
			for _, o := range opts {
				if toKeep, blinkstick := o(di); toKeep {
					out = append(out, blinkstick)
				}
			}

		}
	}
	return out
}
<|endoftext|>


<commit_before>package wal

import (
	"errors"
	"io"
	"io/ioutil"
	"os"

	"github.com/NebulousLabs/fastrand"
)

// These interfaces define the wal's dependencies. Using the smallest
// interface possible makes it easier to mock these dependencies in testing.
type (
	dependencies interface {
		disrupt(string) bool
		readFile(string) ([]byte, error)
		openFile(string, int, os.FileMode) (file, error)
		create(string) (file, error)
	}

	// file implements all of the methods that can be called on an os.File.
	file interface {
		io.ReadWriteCloser
		Name() string
		ReadAt([]byte, int64) (int, error)
		Sync() error
		WriteAt([]byte, int64) (int, error)
		Stat() (os.FileInfo, error)
	}
)

// dependencyCommitFail corrupts the first page of a transaction when it
// is committed
type dependencyCommitFail struct {
	prodDependencies
}

func (dependencyCommitFail) disrupt(s string) bool {
	if s == "CommitFail" {
		return true
	}
	return false
}

// dependencyReleaseFail corrupts the first page of a transaction when it
// is released
type dependencyReleaseFail struct {
	prodDependencies
}

func (dependencyReleaseFail) disrupt(s string) bool {
	if s == "ReleaseFail" {
		return true
	}
	return false
}

// prodDependencies is a passthrough to the standard library calls
type prodDependencies struct{}

func (prodDependencies) disrupt(string) bool { return false }
func (prodDependencies) readFile(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}
func (prodDependencies) openFile(path string, flag int, perm os.FileMode) (file, error) {
	return os.OpenFile(path, flag, perm)
}
func (prodDependencies) create(path string) (file, error) {
	return os.Create(path)
}

// faultyFile implements a file that simulates a faulty disk.
type faultyFile struct {
	file   *os.File
	failed bool
}

func (f *faultyFile) Read(p []byte) (int, error) {
	return f.file.Read(p)
}
func (f *faultyFile) Write(p []byte) (int, error) {
	fail := fastrand.Intn(2) == 0
	if fail {
		f.failed = true
		return len(p), nil
	}
	return f.file.Write(p)
}
func (f *faultyFile) Close() error { return f.file.Close() }
func (f *faultyFile) Name() string {
	return f.file.Name()
}
func (f *faultyFile) ReadAt(p []byte, off int64) (int, error) {
	return f.file.ReadAt(p, off)
}
func (f *faultyFile) WriteAt(p []byte, off int64) (int, error) {
	fail := fastrand.Intn(2) == 0
	if fail {
		f.failed = true
		return len(p), nil
	}
	return f.file.WriteAt(p, off)
}
func (f *faultyFile) Stat() (os.FileInfo, error) {
	return f.file.Stat()
}
func (f *faultyFile) Sync() error {
	if f.failed {
		return errors.New("could not write to disk (faultyDisk)")
	}
	return f.file.Sync()
}

// faultyDiskDependency implements dependencies that simulate a faulty disk.
type faultyDiskDependency struct{}

func (faultyDiskDependency) disrupt(s string) bool {
	return false
}
func (faultyDiskDependency) readFile(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}
func (faultyDiskDependency) openFile(path string, flag int, perm os.FileMode) (file, error) {
	f, err := os.OpenFile(path, flag, perm)
	if err != nil {
		return nil, err
	}
	return &faultyFile{f, false}, nil
}
func (faultyDiskDependency) create(path string) (file, error) {
	f, err := os.Create(path)
	if err != nil {
		return nil, err
	}
	return &faultyFile{f, false}, nil
}
<commit_msg>add failDenominator<commit_after>package wal

import (
	"errors"
	"io"
	"io/ioutil"
	"os"

	"github.com/NebulousLabs/fastrand"
)

// These interfaces define the wal's dependencies. Using the smallest
// interface possible makes it easier to mock these dependencies in testing.
type (
	dependencies interface {
		disrupt(string) bool
		readFile(string) ([]byte, error)
		openFile(string, int, os.FileMode) (file, error)
		create(string) (file, error)
	}

	// file implements all of the methods that can be called on an os.File.
	file interface {
		io.ReadWriteCloser
		Name() string
		ReadAt([]byte, int64) (int, error)
		Sync() error
		WriteAt([]byte, int64) (int, error)
		Stat() (os.FileInfo, error)
	}
)

// dependencyCommitFail corrupts the first page of a transaction when it
// is committed
type dependencyCommitFail struct {
	prodDependencies
}

func (dependencyCommitFail) disrupt(s string) bool {
	if s == "CommitFail" {
		return true
	}
	return false
}

// dependencyReleaseFail corrupts the first page of a transaction when it
// is released
type dependencyReleaseFail struct {
	prodDependencies
}

func (dependencyReleaseFail) disrupt(s string) bool {
	if s == "ReleaseFail" {
		return true
	}
	return false
}

// prodDependencies is a passthrough to the standard library calls
type prodDependencies struct{}

func (prodDependencies) disrupt(string) bool { return false }
func (prodDependencies) readFile(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}
func (prodDependencies) openFile(path string, flag int, perm os.FileMode) (file, error) {
	return os.OpenFile(path, flag, perm)
}
func (prodDependencies) create(path string) (file, error) {
	return os.Create(path)
}

// faultyFile implements a file that simulates a faulty disk.
type faultyFile struct {
	file   *os.File
	failed bool

	// failDenominator determins how likely it is that a write will fail, defined
	// as 1/failDenominator. Each write call increments failDenominator, and it
	// starts at 2. This means that the more calls to WriteAt, the less likely
	// the write is to fail.
	failDenominator int
}

func (f *faultyFile) Read(p []byte) (int, error) {
	return f.file.Read(p)
}
func (f *faultyFile) Write(p []byte) (int, error) {
	fail := fastrand.Intn(f.failDenominator) == 0
	if fail {
		f.failed = true
		return len(p), nil
	}
	f.failDenominator++
	return f.file.Write(p)
}
func (f *faultyFile) Close() error { return f.file.Close() }
func (f *faultyFile) Name() string {
	return f.file.Name()
}
func (f *faultyFile) ReadAt(p []byte, off int64) (int, error) {
	return f.file.ReadAt(p, off)
}
func (f *faultyFile) WriteAt(p []byte, off int64) (int, error) {
	fail := fastrand.Intn(f.failDenominator) == 0
	if fail {
		f.failed = true
		return len(p), nil
	}
	f.failDenominator++
	return f.file.WriteAt(p, off)
}
func (f *faultyFile) Stat() (os.FileInfo, error) {
	return f.file.Stat()
}
func (f *faultyFile) Sync() error {
	if f.failed {
		return errors.New("could not write to disk (faultyDisk)")
	}
	return f.file.Sync()
}

// faultyDiskDependency implements dependencies that simulate a faulty disk.
type faultyDiskDependency struct{}

func (faultyDiskDependency) disrupt(s string) bool {
	return false
}
func (faultyDiskDependency) readFile(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}
func (faultyDiskDependency) openFile(path string, flag int, perm os.FileMode) (file, error) {
	f, err := os.OpenFile(path, flag, perm)
	if err != nil {
		return nil, err
	}
	return &faultyFile{f, false, 2}, nil
}
func (faultyDiskDependency) create(path string) (file, error) {
	f, err := os.Create(path)
	if err != nil {
		return nil, err
	}
	return &faultyFile{f, false, 2}, nil
}
<|endoftext|>


<commit_before>package wal

import (
	"errors"
	"io"
	"io/ioutil"
	"os"

	"github.com/NebulousLabs/fastrand"
)

// These interfaces define the wal's dependencies. Using the smallest
// interface possible makes it easier to mock these dependencies in testing.
type (
	dependencies interface {
		disrupt(string) bool
		readFile(string) ([]byte, error)
		openFile(string, int, os.FileMode) (file, error)
		create(string) (file, error)
	}

	// file implements all of the methods that can be called on an os.File.
	file interface {
		io.ReadWriteCloser
		Name() string
		ReadAt([]byte, int64) (int, error)
		Sync() error
		WriteAt([]byte, int64) (int, error)
		Stat() (os.FileInfo, error)
	}
)

// dependencyCommitFail corrupts the first page of a transaction when it
// is committed
type dependencyCommitFail struct {
	prodDependencies
}

func (dependencyCommitFail) disrupt(s string) bool {
	if s == "CommitFail" {
		return true
	}
	return false
}

// dependencyReleaseFail corrupts the first page of a transaction when it
// is released
type dependencyReleaseFail struct {
	prodDependencies
}

func (dependencyReleaseFail) disrupt(s string) bool {
	if s == "ReleaseFail" {
		return true
	}
	return false
}

// prodDependencies is a passthrough to the standard library calls
type prodDependencies struct{}

func (prodDependencies) disrupt(string) bool { return false }
func (prodDependencies) readFile(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}
func (prodDependencies) openFile(path string, flag int, perm os.FileMode) (file, error) {
	return os.OpenFile(path, flag, perm)
}
func (prodDependencies) create(path string) (file, error) {
	return os.Create(path)
}

// faultyFile implements a file that simulates a faulty disk.
type faultyFile struct {
	file   *os.File
	failed bool

	// failDenominator determins how likely it is that a write will fail, defined
	// as 1/failDenominator. Each write call increments failDenominator, and it
	// starts at 2. This means that the more calls to WriteAt, the less likely
	// the write is to fail. All calls will start automatically failing after
	// 5000 writes.
	failDenominator int
}

func (f *faultyFile) Read(p []byte) (int, error) {
	return f.file.Read(p)
}
func (f *faultyFile) Write(p []byte) (int, error) {
	fail := fastrand.Intn(f.failDenominator) == 0
	f.failDenominator++
	if fail || f.failDenominator >= 5000 {
		f.failed = true
		return len(p), nil
	}
	return f.file.Write(p)
}
func (f *faultyFile) Close() error { return f.file.Close() }
func (f *faultyFile) Name() string {
	return f.file.Name()
}
func (f *faultyFile) ReadAt(p []byte, off int64) (int, error) {
	return f.file.ReadAt(p, off)
}
func (f *faultyFile) WriteAt(p []byte, off int64) (int, error) {
	fail := fastrand.Intn(f.failDenominator) == 0
	f.failDenominator++
	if fail || f.failDenominator >= 5000 {
		f.failed = true
		return len(p), nil
	}
	return f.file.WriteAt(p, off)
}
func (f *faultyFile) Stat() (os.FileInfo, error) {
	return f.file.Stat()
}
func (f *faultyFile) Sync() error {
	if f.failed {
		return errors.New("could not write to disk (faultyDisk)")
	}
	return f.file.Sync()
}

// faultyDiskDependency implements dependencies that simulate a faulty disk.
type faultyDiskDependency struct{}

func (faultyDiskDependency) disrupt(s string) bool {
	return s == "FaultyDisk"
}
func (faultyDiskDependency) readFile(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}
func (faultyDiskDependency) openFile(path string, flag int, perm os.FileMode) (file, error) {
	f, err := os.OpenFile(path, flag, perm)
	if err != nil {
		return nil, err
	}
	return &faultyFile{f, false, 3}, nil
}
func (faultyDiskDependency) create(path string) (file, error) {
	f, err := os.Create(path)
	if err != nil {
		return nil, err
	}
	return &faultyFile{f, false, 3}, nil
}
<commit_msg>fix faultyfile race<commit_after>package wal

import (
	"errors"
	"io"
	"io/ioutil"
	"os"
	"sync"

	"github.com/NebulousLabs/fastrand"
)

// These interfaces define the wal's dependencies. Using the smallest
// interface possible makes it easier to mock these dependencies in testing.
type (
	dependencies interface {
		disrupt(string) bool
		readFile(string) ([]byte, error)
		openFile(string, int, os.FileMode) (file, error)
		create(string) (file, error)
	}

	// file implements all of the methods that can be called on an os.File.
	file interface {
		io.ReadWriteCloser
		Name() string
		ReadAt([]byte, int64) (int, error)
		Sync() error
		WriteAt([]byte, int64) (int, error)
		Stat() (os.FileInfo, error)
	}
)

// dependencyCommitFail corrupts the first page of a transaction when it
// is committed
type dependencyCommitFail struct {
	prodDependencies
}

func (dependencyCommitFail) disrupt(s string) bool {
	if s == "CommitFail" {
		return true
	}
	return false
}

// dependencyReleaseFail corrupts the first page of a transaction when it
// is released
type dependencyReleaseFail struct {
	prodDependencies
}

func (dependencyReleaseFail) disrupt(s string) bool {
	if s == "ReleaseFail" {
		return true
	}
	return false
}

// prodDependencies is a passthrough to the standard library calls
type prodDependencies struct{}

func (prodDependencies) disrupt(string) bool { return false }
func (prodDependencies) readFile(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}
func (prodDependencies) openFile(path string, flag int, perm os.FileMode) (file, error) {
	return os.OpenFile(path, flag, perm)
}
func (prodDependencies) create(path string) (file, error) {
	return os.Create(path)
}

// faultyFile implements a file that simulates a faulty disk.
type faultyFile struct {
	file   *os.File
	failed bool

	// failDenominator determins how likely it is that a write will fail, defined
	// as 1/failDenominator. Each write call increments failDenominator, and it
	// starts at 2. This means that the more calls to WriteAt, the less likely
	// the write is to fail. All calls will start automatically failing after
	// 5000 writes.
	failDenominator int

	mu sync.Mutex
}

func (f *faultyFile) Read(p []byte) (int, error) {
	return f.file.Read(p)
}
func (f *faultyFile) Write(p []byte) (int, error) {
	f.mu.Lock()
	defer f.mu.Unlock()

	fail := fastrand.Intn(f.failDenominator) == 0
	f.failDenominator++
	if fail || f.failDenominator >= 5000 {
		f.failed = true
		return len(p), nil
	}
	return f.file.Write(p)
}
func (f *faultyFile) Close() error { return f.file.Close() }
func (f *faultyFile) Name() string {
	return f.file.Name()
}
func (f *faultyFile) ReadAt(p []byte, off int64) (int, error) {
	return f.file.ReadAt(p, off)
}
func (f *faultyFile) WriteAt(p []byte, off int64) (int, error) {
	f.mu.Lock()
	defer f.mu.Unlock()

	fail := fastrand.Intn(f.failDenominator) == 0
	f.failDenominator++
	if fail || f.failDenominator >= 5000 {
		f.failed = true
		return len(p), nil
	}
	return f.file.WriteAt(p, off)
}
func (f *faultyFile) Stat() (os.FileInfo, error) {
	return f.file.Stat()
}
func (f *faultyFile) Sync() error {
	f.mu.Lock()
	defer f.mu.Unlock()

	if f.failed {
		return errors.New("could not write to disk (faultyDisk)")
	}
	return f.file.Sync()
}

// newFaultyFile creates a new faulty file around the provided file handle.
func newFaultyFile(f *os.File) *faultyFile {
	return &faultyFile{file: f, failed: false, failDenominator: 3}
}

// faultyDiskDependency implements dependencies that simulate a faulty disk.
type faultyDiskDependency struct{}

func (faultyDiskDependency) disrupt(s string) bool {
	return s == "FaultyDisk"
}
func (faultyDiskDependency) readFile(path string) ([]byte, error) {
	return ioutil.ReadFile(path)
}
func (faultyDiskDependency) openFile(path string, flag int, perm os.FileMode) (file, error) {
	f, err := os.OpenFile(path, flag, perm)
	if err != nil {
		return nil, err
	}
	return newFaultyFile(f), nil
}
func (faultyDiskDependency) create(path string) (file, error) {
	f, err := os.Create(path)
	if err != nil {
		return nil, err
	}
	return newFaultyFile(f), nil
}
<|endoftext|>


<commit_before>package bootstrap

import (
	ct "github.com/flynn/flynn/controller/types"
)

type ScaleAppAction struct {
	AppStep string `json:"app_step"`

	*ct.Formation
}

func init() {
	Register("scale-app", &ScaleAppAction{})
}

func (a *ScaleAppAction) Run(s *State) error {
	client, err := s.ControllerClient()
	if err != nil {
		return err
	}
	data, err := getAppStep(s, a.AppStep)
	if err != nil {
		return err
	}

	a.Formation.AppID = data.App.ID
	a.Formation.ReleaseID = data.Release.ID

	for name, count := range a.Formation.Processes {
		if s.Singleton && count > 1 {
			a.Formation.Processes[name] = 1
		}
	}

	return client.PutFormation(a.Formation)
}
<commit_msg>bootstrap: Don’t require AppStep in ScaleAppAction<commit_after>package bootstrap

import (
	ct "github.com/flynn/flynn/controller/types"
)

type ScaleAppAction struct {
	AppStep string `json:"app_step"`

	*ct.Formation
}

func init() {
	Register("scale-app", &ScaleAppAction{})
}

func (a *ScaleAppAction) Run(s *State) error {
	client, err := s.ControllerClient()
	if err != nil {
		return err
	}
	if a.AppStep != "" {
		data, err := getAppStep(s, a.AppStep)
		if err != nil {
			return err
		}
		a.Formation.AppID = data.App.ID
		a.Formation.ReleaseID = data.Release.ID
	}

	for name, count := range a.Formation.Processes {
		if s.Singleton && count > 1 {
			a.Formation.Processes[name] = 1
		}
	}

	return client.PutFormation(a.Formation)
}
<|endoftext|>


<commit_before>// +build ignore

package main

import (
	"fmt"
	"os"
)

type S int

var theS S

func (s *S) String() string {
	print(s) // @pointsto main.theS
	return ""
}

func main() {
	print(os.Args) // @pointsto <command-line args>
	fmt.Println("Hello, World!", &theS)
}

// @calls main.main               -> fmt.Println
// @calls (*fmt.pp).handleMethods -> (*main.S).String
<commit_msg>go.tools/pointer: fix test of pts(os.Args) on Windows.<commit_after>// +build ignore

package main

import (
	"fmt"
	"os"
)

type S int

var theS S

func (s *S) String() string {
	print(s) // @pointsto main.theS
	return ""
}

func main() {
	// os.Args is considered instrincally allocated,
	// but may also be set explicitly (e.g. on Windows), hence '...'.
	print(os.Args) // @pointsto <command-line args> | ...
	fmt.Println("Hello, World!", &theS)
}

// @calls main.main               -> fmt.Println
// @calls (*fmt.pp).handleMethods -> (*main.S).String
<|endoftext|>


<commit_before>package compress

import "strconv"

func compress(uncompressed string) string {
	var buf string

	if len(uncompressed) == 0 {
		return buf
	}

	var prev byte
	letter := uncompressed[0]
	last := 0
	for i := 1; i < len(uncompressed); i++ {
		prev = uncompressed[i-1]
		letter = uncompressed[i]
		if letter != prev {
			buf += string(prev)
			buf += strconv.Itoa(i - last)
			last = i
		}
	}
	buf += string(letter)
	buf += strconv.Itoa(len(uncompressed) - last)

	return buf
}
<commit_msg>Use range instead<commit_after>package compress

import "fmt"

func compress(uncompressed string) string {
	var buf string

	if len(uncompressed) == 0 {
		return buf
	}

	letter := string(uncompressed[0])
	count := 1
	for _, next := range uncompressed[1:] {
		if letter == string(next) {
			count++
		} else {
			buf += fmt.Sprintf("%s%d", letter, count)
			count = 1
		}
		letter = string(next)
	}
	buf += fmt.Sprintf("%s%d", letter, count)

	return buf
}
<|endoftext|>


<commit_before>// for window OS

package printer

const (
	DoneSignW = "V"
	UndoneSignW = "X"
)<commit_msg>fix convention with gofmt<commit_after>// for window OS

package printer

const (
	DoneSignW   = "V"
	UndoneSignW = "X"
)
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package json

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/zouyx/agollo/v4/env/config"
	"sync"

	"github.com/zouyx/agollo/v4/component/log"
	jsonConfig "github.com/zouyx/agollo/v4/env/config/json"
)

//Suffix 默认文件保存类型
const Suffix = ".json"

var (
	//jsonFileConfig 处理文件的json格式存取
	jsonFileConfig = &jsonConfig.ConfigFile{}
	//configFileMap 存取namespace文件地址
	configFileMap = make(map[string]string, 1)
	//configFileMapLock configFileMap的读取锁
	configFileMapLock sync.Mutex
)

// FileHandler 默认备份文件读写
type FileHandler struct {
}

// WriteConfigFile write config to file
func (fileHandler *FileHandler) WriteConfigFile(config *config.ApolloConfig, configPath string) error {
	return jsonFileConfig.Write(config, fileHandler.GetConfigFile(configPath, config.AppID, config.NamespaceName))
}

// GetConfigFile get real config file
func (fileHandler *FileHandler) GetConfigFile(configDir string, appID string, namespace string) string {
	key := fmt.Sprintf("%s-%s", appID, namespace)
	configFileMapLock.Lock()
	defer configFileMapLock.Unlock()
	fullPath := configFileMap[key]
	if fullPath == "" {
		filePath := fmt.Sprintf("%s%s", key, Suffix)
		if configDir != "" {
			configFileMap[namespace] = fmt.Sprintf("%s/%s", configDir, filePath)
		} else {
			configFileMap[namespace] = filePath
		}
	}
	return configFileMap[namespace]
}

//LoadConfigFile load config from file
func (fileHandler *FileHandler) LoadConfigFile(configDir string, appID string, namespace string) (*config.ApolloConfig, error) {
	configFilePath := fileHandler.GetConfigFile(configDir, appID, namespace)
	log.Info("load config file from :", configFilePath)
	c, e := jsonFileConfig.Load(configFilePath, func(b []byte) (interface{}, error) {
		config := &config.ApolloConfig{}
		e := json.NewDecoder(bytes.NewBuffer(b)).Decode(config)
		return config, e
	})

	if c == nil || e != nil {
		log.Errorf("loadConfigFile fail,error:", e)
		return nil, e
	}

	return c.(*config.ApolloConfig), e
}
<commit_msg>Revert "fix concurrency problem"<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package json

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/zouyx/agollo/v4/env/config"

	"github.com/zouyx/agollo/v4/component/log"
	jsonConfig "github.com/zouyx/agollo/v4/env/config/json"
)

//Suffix 默认文件保存类型
const Suffix = ".json"

var (
	//jsonFileConfig 处理文件的json格式存取
	jsonFileConfig = &jsonConfig.ConfigFile{}
	//configFileMap 存取namespace文件地址
	configFileMap = make(map[string]string, 1)
)

// FileHandler 默认备份文件读写
type FileHandler struct {
}

// WriteConfigFile write config to file
func (fileHandler *FileHandler) WriteConfigFile(config *config.ApolloConfig, configPath string) error {
	return jsonFileConfig.Write(config, fileHandler.GetConfigFile(configPath, config.AppID, config.NamespaceName))
}

// GetConfigFile get real config file
func (fileHandler *FileHandler) GetConfigFile(configDir string, appID string, namespace string) string {
	key := fmt.Sprintf("%s-%s", appID, namespace)
	fullPath := configFileMap[key]
	if fullPath == "" {
		filePath := fmt.Sprintf("%s%s", key, Suffix)
		if configDir != "" {
			configFileMap[namespace] = fmt.Sprintf("%s/%s", configDir, filePath)
		} else {
			configFileMap[namespace] = filePath
		}
	}
	return configFileMap[namespace]
}

//LoadConfigFile load config from file
func (fileHandler *FileHandler) LoadConfigFile(configDir string, appID string, namespace string) (*config.ApolloConfig, error) {
	configFilePath := fileHandler.GetConfigFile(configDir, appID, namespace)
	log.Info("load config file from :", configFilePath)
	c, e := jsonFileConfig.Load(configFilePath, func(b []byte) (interface{}, error) {
		config := &config.ApolloConfig{}
		e := json.NewDecoder(bytes.NewBuffer(b)).Decode(config)
		return config, e
	})

	if c == nil || e != nil {
		log.Errorf("loadConfigFile fail,error:", e)
		return nil, e
	}

	return c.(*config.ApolloConfig), e
}
<|endoftext|>


<commit_before>package errors_test

import (
	"fmt"
	"strings"
	"testing"

	uerrors "github.com/Akagi201/utilgo/errors"
	"github.com/pkg/errors"
	"github.com/stretchr/testify/assert"
)

func TestFrom(t *testing.T) {
	err := uerrors.From(errors.New("hello"))

	assert.EqualError(t, err, "hello")

	assert.Nil(t, err.Cause())
	assert.Nil(t, errors.Cause(err))

	stacktrace := err.StackTrace()
	assert.NotNil(t, stacktrace)
	assert.NotEmpty(t, stacktrace)

	nothing, ok := uerrors.Get(err, nil)
	assert.False(t, ok)
	assert.Nil(t, nothing)

	nothing, ok = uerrors.Get(err, "nope")
	assert.False(t, ok)
	assert.Nil(t, nothing)
}

func TestCause(t *testing.T) {
	cause := errors.New("cause")
	middle := errors.Wrap(cause, "middle")
	outer := errors.Wrap(middle, "outer")
	err := uerrors.From(outer)

	assert.EqualError(t, err, "outer: middle: cause")

	assert.Equal(t, cause, errors.Cause(err))
}

func TestFormatNoProps(t *testing.T) {
	cause := errors.New("cause")
	err := uerrors.From(cause)

	assert.Equal(t, "cause", fmt.Sprintf("%v", err))

	formatted := fmt.Sprintf("%+v", err)
	prefix := `cause
github.com/Akagi201/utilgo/errors_test.TestFormatNoProps
	` // The rest of the string will have device-specific components (paths, CPU).

	assert.True(t, strings.HasPrefix(formatted, prefix),
		"expected\n%s\nto have prefix\n%s", formatted, prefix)
	assert.Contains(t, formatted, "github.com/Akagi201/utilgo/errors/errors_test.go:")
}

func TestFormatWithProps(t *testing.T) {
	err := uerrors.From(errors.New("cause")).
		WithValue(struct{ Id int }{1}, 2).
		WithValue("key", "value")

	assert.Equal(t, "[key=value,{1}=2] cause", fmt.Sprintf("%v", err))

	formatted := fmt.Sprintf("%+v", err)
	prefix := `[key=value,{Id:1}=2] cause
github.com/Akagi201/utilgo/errors_test.TestFormatWithProps
	` // The rest of the string will have device-specific components (paths, CPU).

	assert.True(t, strings.HasPrefix(formatted, prefix),
		"expected\n%s\nto have prefix\n%s", formatted, prefix)
	assert.Contains(t, formatted, "github.com/Akagi201/utilgo/errors/errors_test.go:")
}

func TestWithValue(t *testing.T) {
	err := uerrors.From(errors.New("hello"))

	withFooBar := err.WithValue("foo", "bar")
	assertHasPropOnSelf(t, withFooBar, "foo", "bar")
	// Get should only check keys, not values.
	assertDoesNotHaveProp(t, withFooBar, "bar")

	// Change the value.
	withFooBaz := withFooBar.WithValue("foo", "baz")
	assertHasPropOnSelf(t, withFooBaz, "foo", "baz")
	// Original error should remain unchanged.
	assertHasPropOnSelf(t, withFooBar, "foo", "bar")

	// Add another value.
	withFooBazKeyValue := withFooBaz.WithValue("key", "value")
	assertHasPropOnSelf(t, withFooBazKeyValue, "key", "value")
	assertHasPropOnSelf(t, withFooBaz, "foo", "baz")
}

func TestGetIntermediateCauseHasProp(t *testing.T) {
	cause := errors.New("root cause")
	middle := uerrors.From(errors.Wrap(cause, "")).
		WithValue("foo", "bar")
	err := errors.Wrap(middle, "")

	assertHasProp(t, err, "foo", "bar")

	// Wrapping with another PropError shouldn't change the results.
	err = uerrors.From(err)
	assertDoesNotHavePropOnSelf(t, err.(uerrors.ContextError), "foo")
	assertHasProp(t, err, "foo", "bar")
}

func TestGetRootCauseHasProp(t *testing.T) {
	cause := uerrors.From(errors.New("root cause")).
		WithValue("foo", "bar")
	middle := errors.Wrap(cause, "")
	err := errors.Wrap(middle, "")

	assertHasProp(t, err, "foo", "bar")

	// Wrapping with another PropError shouldn't change the results.
	err = uerrors.From(err)
	assertDoesNotHavePropOnSelf(t, err.(uerrors.ContextError), "foo")
	assertHasProp(t, err, "foo", "bar")
}

func assertHasPropOnSelf(t *testing.T, err uerrors.ContextError, key, wantVal interface{}) {
	val, ok := err.Get(key)
	assert.True(t, ok)
	assert.Equal(t, wantVal, val)
	assertHasProp(t, err, key, wantVal)
}

// Like assertHasPropOnSelf but calls the package Get to recurse through causes.
func assertHasProp(t *testing.T, err error, key, wantVal interface{}) {
	assert.Equal(t, wantVal, uerrors.GetOpt(err, key))
	val, ok := uerrors.Get(err, key)
	assert.True(t, ok)
	assert.Equal(t, wantVal, val)
}

func assertDoesNotHavePropOnSelf(t *testing.T, err uerrors.ContextError, key interface{}) {
	val, ok := err.Get(key)
	assert.False(t, ok)
	assert.Nil(t, val)
}

// Like assertDoesNotHavePropOnSelf but calls the package Get to recurse through causes.
func assertDoesNotHaveProp(t *testing.T, err error, key interface{}) {
	assert.Nil(t, uerrors.GetOpt(err, key))
	val, ok := uerrors.Get(err, key)
	assert.False(t, ok)
	assert.Nil(t, val)

	if err, ok := err.(uerrors.ContextError); ok {
		assertDoesNotHavePropOnSelf(t, err, key)
	}
}
<commit_msg>fix(errors): fix some device specific check<commit_after>package errors_test

import (
	"fmt"
	"strings"
	"testing"

	uerrors "github.com/Akagi201/utilgo/errors"
	"github.com/pkg/errors"
	"github.com/stretchr/testify/assert"
)

func TestFrom(t *testing.T) {
	err := uerrors.From(errors.New("hello"))

	assert.EqualError(t, err, "hello")

	assert.Nil(t, err.Cause())
	assert.Nil(t, errors.Cause(err))

	stacktrace := err.StackTrace()
	assert.NotNil(t, stacktrace)
	assert.NotEmpty(t, stacktrace)

	nothing, ok := uerrors.Get(err, nil)
	assert.False(t, ok)
	assert.Nil(t, nothing)

	nothing, ok = uerrors.Get(err, "nope")
	assert.False(t, ok)
	assert.Nil(t, nothing)
}

func TestCause(t *testing.T) {
	cause := errors.New("cause")
	middle := errors.Wrap(cause, "middle")
	outer := errors.Wrap(middle, "outer")
	err := uerrors.From(outer)

	assert.EqualError(t, err, "outer: middle: cause")

	assert.Equal(t, cause, errors.Cause(err))
}

func TestFormatNoProps(t *testing.T) {
	cause := errors.New("cause")
	err := uerrors.From(cause)

	assert.Equal(t, "cause", fmt.Sprintf("%v", err))

	formatted := fmt.Sprintf("%+v", err)
	prefix := `cause`
	path := `github.com/Akagi201/utilgo/errors_test.TestFormatNoProps`
	// The rest of the string will have device-specific components (paths, CPU).

	assert.True(t, strings.HasPrefix(formatted, prefix), "expected\n%s\nto have prefix\n%s",
		formatted, prefix)
	assert.True(t, strings.Contains(formatted, path),
		"expected\n%s\nto contain\n%s", formatted, path)
	assert.Contains(t, formatted, "github.com/Akagi201/utilgo/errors/errors_test.go:")
}

func TestFormatWithProps(t *testing.T) {
	err := uerrors.From(errors.New("cause")).
		WithValue(struct{ Id int }{1}, 2).
		WithValue("key", "value")

	assert.Equal(t, "[key=value,{1}=2] cause", fmt.Sprintf("%v", err))

	formatted := fmt.Sprintf("%+v", err)
	prefix := `[key=value,{Id:1}=2] cause`
	path := `github.com/Akagi201/utilgo/errors_test.TestFormatWithProps`
	// The rest of the string will have device-specific components (paths, CPU).

	assert.True(t, strings.HasPrefix(formatted, prefix), "expected\n%s\nto contain\n%s",
		formatted, prefix)
	assert.True(t, strings.Contains(formatted, path),
		"expected\n%s\nto contain\n%s", formatted, path)
	assert.Contains(t, formatted, "github.com/Akagi201/utilgo/errors/errors_test.go:")
}

func TestWithValue(t *testing.T) {
	err := uerrors.From(errors.New("hello"))

	withFooBar := err.WithValue("foo", "bar")
	assertHasPropOnSelf(t, withFooBar, "foo", "bar")
	// Get should only check keys, not values.
	assertDoesNotHaveProp(t, withFooBar, "bar")

	// Change the value.
	withFooBaz := withFooBar.WithValue("foo", "baz")
	assertHasPropOnSelf(t, withFooBaz, "foo", "baz")
	// Original error should remain unchanged.
	assertHasPropOnSelf(t, withFooBar, "foo", "bar")

	// Add another value.
	withFooBazKeyValue := withFooBaz.WithValue("key", "value")
	assertHasPropOnSelf(t, withFooBazKeyValue, "key", "value")
	assertHasPropOnSelf(t, withFooBaz, "foo", "baz")
}

func TestGetIntermediateCauseHasProp(t *testing.T) {
	cause := errors.New("root cause")
	middle := uerrors.From(errors.Wrap(cause, "")).
		WithValue("foo", "bar")
	err := errors.Wrap(middle, "")

	assertHasProp(t, err, "foo", "bar")

	// Wrapping with another PropError shouldn't change the results.
	err = uerrors.From(err)
	assertDoesNotHavePropOnSelf(t, err.(uerrors.ContextError), "foo")
	assertHasProp(t, err, "foo", "bar")
}

func TestGetRootCauseHasProp(t *testing.T) {
	cause := uerrors.From(errors.New("root cause")).
		WithValue("foo", "bar")
	middle := errors.Wrap(cause, "")
	err := errors.Wrap(middle, "")

	assertHasProp(t, err, "foo", "bar")

	// Wrapping with another PropError shouldn't change the results.
	err = uerrors.From(err)
	assertDoesNotHavePropOnSelf(t, err.(uerrors.ContextError), "foo")
	assertHasProp(t, err, "foo", "bar")
}

func assertHasPropOnSelf(t *testing.T, err uerrors.ContextError, key, wantVal interface{}) {
	val, ok := err.Get(key)
	assert.True(t, ok)
	assert.Equal(t, wantVal, val)
	assertHasProp(t, err, key, wantVal)
}

// Like assertHasPropOnSelf but calls the package Get to recurse through causes.
func assertHasProp(t *testing.T, err error, key, wantVal interface{}) {
	assert.Equal(t, wantVal, uerrors.GetOpt(err, key))
	val, ok := uerrors.Get(err, key)
	assert.True(t, ok)
	assert.Equal(t, wantVal, val)
}

func assertDoesNotHavePropOnSelf(t *testing.T, err uerrors.ContextError, key interface{}) {
	val, ok := err.Get(key)
	assert.False(t, ok)
	assert.Nil(t, val)
}

// Like assertDoesNotHavePropOnSelf but calls the package Get to recurse through causes.
func assertDoesNotHaveProp(t *testing.T, err error, key interface{}) {
	assert.Nil(t, uerrors.GetOpt(err, key))
	val, ok := uerrors.Get(err, key)
	assert.False(t, ok)
	assert.Nil(t, val)

	if err, ok := err.(uerrors.ContextError); ok {
		assertDoesNotHavePropOnSelf(t, err, key)
	}
}
<|endoftext|>


<commit_before>package Crypt

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"io"
)

func PKCS5Padding(src []byte, block_size int) []byte {
	padding := block_size - len(src)%block_size
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(src, padtext...)
}

func PKCS5UnPadding(src []byte, block_size int) ([]byte, error) {
	length := len(src)
	padding := int(src[length-1])
	if padding < 0 || padding > length {
		return nil, errors.New("PKCS5UnPadding error")
	}
	return src[:length-padding], nil
}

func Encrypt(block cipher.Block, plaintext []byte, key []byte) ([]byte, error) {
	block_size := block.BlockSize()
	plaintext = PKCS5Padding(plaintext, block_size)

	ciphertext := make([]byte, block_size+len(plaintext))
	iv := ciphertext[:block_size]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}

	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(ciphertext[block_size:], plaintext)

	return ciphertext, nil
}

func Decrypt(block cipher.Block, ciphertext []byte, key []byte) ([]byte, error) {
	block_size := block.BlockSize()

	if len(ciphertext) < block_size {
		return nil, errors.New("Decrypt failed: uncomplete ciphertext")
	}
	iv := ciphertext[:block_size]
	ciphertext = ciphertext[block_size:]

	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(ciphertext, ciphertext)

	return PKCS5UnPadding(ciphertext, block_size)
}

func AesEncrypt(plaintext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	return Encrypt(block, plaintext, key)
}

func AesDecrypt(ciphertext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	return Decrypt(block, ciphertext, key)
}<commit_msg>Update aes.go<commit_after>// Copyright 2017 Gruppe 12 IS-105. All rights reserved.
package Crypt

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"io"
)

func PKCS5Padding(src []byte, block_size int) []byte {
	padding := block_size - len(src)%block_size
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(src, padtext...)
}

func PKCS5UnPadding(src []byte, block_size int) ([]byte, error) {
	length := len(src)
	padding := int(src[length-1])
	if padding < 0 || padding > length {
		return nil, errors.New("PKCS5UnPadding error")
	}
	return src[:length-padding], nil
}

func Encrypt(block cipher.Block, plaintext []byte, key []byte) ([]byte, error) {
	block_size := block.BlockSize()
	plaintext = PKCS5Padding(plaintext, block_size)

	ciphertext := make([]byte, block_size+len(plaintext))
	iv := ciphertext[:block_size]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}

	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(ciphertext[block_size:], plaintext)

	return ciphertext, nil
}

func Decrypt(block cipher.Block, ciphertext []byte, key []byte) ([]byte, error) {
	block_size := block.BlockSize()

	if len(ciphertext) < block_size {
		return nil, errors.New("Decrypt failed: uncomplete ciphertext")
	}
	iv := ciphertext[:block_size]
	ciphertext = ciphertext[block_size:]

	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(ciphertext, ciphertext)

	return PKCS5UnPadding(ciphertext, block_size)
}

func AesEncrypt(plaintext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	return Encrypt(block, plaintext, key)
}

func AesDecrypt(ciphertext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	return Decrypt(block, ciphertext, key)
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs_test

import (
	"strings"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/bootstrap"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/environs/configstore"
	envtesting "launchpad.net/juju-core/environs/testing"
	"launchpad.net/juju-core/errors"
	"launchpad.net/juju-core/provider/dummy"
	"launchpad.net/juju-core/testing"
	jc "launchpad.net/juju-core/testing/checkers"
)

type OpenSuite struct {
	envtesting.ToolsFixture
}

var _ = gc.Suite(&OpenSuite{})

func (OpenSuite) TearDownTest(c *gc.C) {
	dummy.Reset()
}

func (OpenSuite) TestNewDummyEnviron(c *gc.C) {
	// matches *Settings.Map()
	cfg, err := config.New(config.NoDefaults, dummySampleConfig())
	c.Assert(err, gc.IsNil)
	env, err := environs.Prepare(cfg, configstore.NewMem())
	c.Assert(err, gc.IsNil)
	c.Assert(bootstrap.Bootstrap(env, constraints.Value{}), gc.IsNil)
}

func (OpenSuite) TestNewUnknownEnviron(c *gc.C) {
	attrs := dummySampleConfig().Merge(testing.Attrs{
		"type": "wondercloud",
	})
	env, err := environs.NewFromAttrs(attrs)
	c.Assert(err, gc.ErrorMatches, "no registered provider for.*")
	c.Assert(env, gc.IsNil)
}

func (OpenSuite) TestNewFromName(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
	e, err := environs.NewFromName("erewhemos")
	c.Assert(err, gc.IsNil)
	c.Assert(e.Name(), gc.Equals, "erewhemos")
	c.Assert(func() { e.Storage() }, gc.PanicMatches, "environment .* is not prepared")
}

func (OpenSuite) TestNewFromNameNoDefault(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()

	e, err := environs.NewFromName("")
	c.Assert(err, gc.ErrorMatches, "no default environment found")
	c.Assert(e, gc.IsNil)
}

func (OpenSuite) TestNewFromNameDefault(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.SingleEnvConfig, testing.SampleCertName).Restore()
	e, err := environs.NewFromName("")
	c.Assert(err, gc.IsNil)
	c.Assert(e.Name(), gc.Equals, "erewhemos")
}

func (OpenSuite) TestPrepareFromName(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
	e, err := environs.PrepareFromName("erewhemos", configstore.NewMem())
	c.Assert(err, gc.IsNil)
	c.Assert(e.Name(), gc.Equals, "erewhemos")
	// Check we can access storage ok, which implies the environment has been prepared.
	c.Assert(e.Storage(), gc.NotNil)
}

func (OpenSuite) TestConfigForName(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
	cfg, err := environs.ConfigForName("erewhemos")
	c.Assert(err, gc.IsNil)
	c.Assert(cfg.Name(), gc.Equals, "erewhemos")
}

func (OpenSuite) TestConfigForNameNoDefault(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
	_, err := environs.ConfigForName("")
	c.Assert(err, gc.ErrorMatches, "no default environment found")
}

func (OpenSuite) TestConfigForNameDefault(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.SingleEnvConfig, testing.SampleCertName).Restore()
	cfg, err := environs.ConfigForName("")
	c.Assert(err, gc.IsNil)
	c.Assert(cfg.Name(), gc.Equals, "erewhemos")
}

func (OpenSuite) TestNew(c *gc.C) {
	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(
		testing.Attrs{
			"state-server": false,
			"name":         "erewhemos",
		},
	))
	c.Assert(err, gc.IsNil)
	e, err := environs.New(cfg)
	c.Assert(err, gc.IsNil)
	c.Assert(func() { e.Storage() }, gc.PanicMatches, "environment .* is not prepared")
}

func (OpenSuite) TestPrepare(c *gc.C) {
	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(
		testing.Attrs{
			"state-server": false,
			"name":         "erewhemos",
		},
	))
	c.Assert(err, gc.IsNil)
	store := configstore.NewMem()
	env, err := environs.Prepare(cfg, store)
	c.Assert(err, gc.IsNil)
	// Check we can access storage ok, which implies the environment has been prepared.
	c.Assert(env.Storage(), gc.NotNil)

	// Check that the environment info file was correctly created.
	info, err := store.ReadInfo("erewhemos")
	c.Assert(err, gc.IsNil)
	c.Assert(info.Initialized(), jc.IsTrue)
	c.Assert(info.BootstrapConfig(), gc.DeepEquals, env.Config().AllAttrs())

	// Check we can call Prepare again.
	env, err = environs.Prepare(cfg, store)
	c.Assert(err, gc.IsNil)
	c.Assert(env.Name(), gc.Equals, "erewhemos")
	c.Assert(env.Storage(), gc.NotNil)
}

func (OpenSuite) TestDestroy(c *gc.C) {
	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(
		testing.Attrs{
			"state-server": false,
			"name":         "erewhemos",
		},
	))
	c.Assert(err, gc.IsNil)

	store := configstore.NewMem()
	// Prepare the environment and sanity-check that
	// the config storage info has been made.
	e, err := environs.Prepare(cfg, store)
	c.Assert(err, gc.IsNil)
	_, err = store.ReadInfo(e.Name())
	c.Assert(err, gc.IsNil)

	err = environs.Destroy(e, store)
	c.Assert(err, gc.IsNil)

	// Check that the environment has actually been destroyed
	// and that the config info has been destroyed too.
	c.Assert(func() { e.Storage() }, gc.PanicMatches, "environment.* is not prepared")
	_, err = store.ReadInfo(e.Name())
	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
}

func (OpenSuite) TestNewFromAttrs(c *gc.C) {
	e, err := environs.NewFromAttrs(dummy.SampleConfig().Merge(
		testing.Attrs{
			"state-server": false,
			"name":         "erewhemos",
		},
	))
	c.Assert(err, gc.IsNil)
	c.Assert(func() { e.Storage() }, gc.PanicMatches, "environment .* is not prepared")
}

const checkEnv = `
environments:
    test:
        type: dummy
        state-server: false
        authorized-keys: i-am-a-key
`

type checkEnvironmentSuite struct{}

var _ = gc.Suite(&checkEnvironmentSuite{})

func (s *checkEnvironmentSuite) TearDownTest(c *gc.C) {
	dummy.Reset()
}

func (s *checkEnvironmentSuite) TestCheckEnvironment(c *gc.C) {
	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()

	environ, err := environs.PrepareFromName("test", configstore.NewMem())
	c.Assert(err, gc.IsNil)

	// VerifyStorage is sufficient for our tests and much simpler
	// than Bootstrap which calls it.
	stor := environ.Storage()
	err = environs.VerifyStorage(stor)
	c.Assert(err, gc.IsNil)
	err = environs.CheckEnvironment(environ)
	c.Assert(err, gc.IsNil)
}

func (s *checkEnvironmentSuite) TestCheckEnvironmentFileNotFound(c *gc.C) {
	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()

	environ, err := environs.PrepareFromName("test", configstore.NewMem())
	c.Assert(err, gc.IsNil)

	// VerifyStorage is sufficient for our tests and much simpler
	// than Bootstrap which calls it.
	stor := environ.Storage()
	err = environs.VerifyStorage(stor)
	c.Assert(err, gc.IsNil)

	// When the bootstrap-verify file does not exist, it still believes
	// the environment is a juju-core one because earlier versions
	// did not create that file.
	err = stor.Remove("bootstrap-verify")
	c.Assert(err, gc.IsNil)
	err = environs.CheckEnvironment(environ)
	c.Assert(err, gc.IsNil)
}

func (s *checkEnvironmentSuite) TestCheckEnvironmentGetFails(c *gc.C) {
	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()

	environ, err := environs.PrepareFromName("test", configstore.NewMem())
	c.Assert(err, gc.IsNil)

	// VerifyStorage is sufficient for our tests and much simpler
	// than Bootstrap which calls it.
	stor := environ.Storage()
	err = environs.VerifyStorage(stor)
	c.Assert(err, gc.IsNil)

	// When fetching the verification file from storage fails,
	// we get an InvalidEnvironmentError.
	someError := errors.Unauthorizedf("you shall not pass")
	dummy.Poison(stor, "bootstrap-verify", someError)
	err = environs.CheckEnvironment(environ)
	c.Assert(err, gc.Equals, someError)
}

func (s *checkEnvironmentSuite) TestCheckEnvironmentBadContent(c *gc.C) {
	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()

	environ, err := environs.PrepareFromName("test", configstore.NewMem())
	c.Assert(err, gc.IsNil)

	// We mock a bad (eg. from a Python-juju environment) bootstrap-verify.
	stor := environ.Storage()
	content := "bad verification content"
	reader := strings.NewReader(content)
	err = stor.Put("bootstrap-verify", reader, int64(len(content)))
	c.Assert(err, gc.IsNil)

	// When the bootstrap-verify file contains unexpected content,
	// we get an InvalidEnvironmentError.
	err = environs.CheckEnvironment(environ)
	c.Assert(err, gc.Equals, environs.InvalidEnvironmentError)
}
<commit_msg>Fix test<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs_test

import (
	"strings"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/bootstrap"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/environs/configstore"
	envtesting "launchpad.net/juju-core/environs/testing"
	"launchpad.net/juju-core/errors"
	"launchpad.net/juju-core/provider/dummy"
	"launchpad.net/juju-core/testing"
	jc "launchpad.net/juju-core/testing/checkers"
)

type OpenSuite struct {
	envtesting.ToolsFixture
}

var _ = gc.Suite(&OpenSuite{})

func (OpenSuite) TearDownTest(c *gc.C) {
	dummy.Reset()
}

func (OpenSuite) TestNewDummyEnviron(c *gc.C) {
	// matches *Settings.Map()
	cfg, err := config.New(config.NoDefaults, dummySampleConfig())
	c.Assert(err, gc.IsNil)
	env, err := environs.Prepare(cfg, configstore.NewMem())
	c.Assert(err, gc.IsNil)
	envtesting.UploadFakeTools(c, env.Storage())
	c.Assert(bootstrap.Bootstrap(env, constraints.Value{}), gc.IsNil)
}

func (OpenSuite) TestNewUnknownEnviron(c *gc.C) {
	attrs := dummySampleConfig().Merge(testing.Attrs{
		"type": "wondercloud",
	})
	env, err := environs.NewFromAttrs(attrs)
	c.Assert(err, gc.ErrorMatches, "no registered provider for.*")
	c.Assert(env, gc.IsNil)
}

func (OpenSuite) TestNewFromName(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
	e, err := environs.NewFromName("erewhemos")
	c.Assert(err, gc.IsNil)
	c.Assert(e.Name(), gc.Equals, "erewhemos")
	c.Assert(func() { e.Storage() }, gc.PanicMatches, "environment .* is not prepared")
}

func (OpenSuite) TestNewFromNameNoDefault(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()

	e, err := environs.NewFromName("")
	c.Assert(err, gc.ErrorMatches, "no default environment found")
	c.Assert(e, gc.IsNil)
}

func (OpenSuite) TestNewFromNameDefault(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.SingleEnvConfig, testing.SampleCertName).Restore()
	e, err := environs.NewFromName("")
	c.Assert(err, gc.IsNil)
	c.Assert(e.Name(), gc.Equals, "erewhemos")
}

func (OpenSuite) TestPrepareFromName(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
	e, err := environs.PrepareFromName("erewhemos", configstore.NewMem())
	c.Assert(err, gc.IsNil)
	c.Assert(e.Name(), gc.Equals, "erewhemos")
	// Check we can access storage ok, which implies the environment has been prepared.
	c.Assert(e.Storage(), gc.NotNil)
}

func (OpenSuite) TestConfigForName(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
	cfg, err := environs.ConfigForName("erewhemos")
	c.Assert(err, gc.IsNil)
	c.Assert(cfg.Name(), gc.Equals, "erewhemos")
}

func (OpenSuite) TestConfigForNameNoDefault(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.MultipleEnvConfigNoDefault, testing.SampleCertName).Restore()
	_, err := environs.ConfigForName("")
	c.Assert(err, gc.ErrorMatches, "no default environment found")
}

func (OpenSuite) TestConfigForNameDefault(c *gc.C) {
	defer testing.MakeFakeHome(c, testing.SingleEnvConfig, testing.SampleCertName).Restore()
	cfg, err := environs.ConfigForName("")
	c.Assert(err, gc.IsNil)
	c.Assert(cfg.Name(), gc.Equals, "erewhemos")
}

func (OpenSuite) TestNew(c *gc.C) {
	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(
		testing.Attrs{
			"state-server": false,
			"name":         "erewhemos",
		},
	))
	c.Assert(err, gc.IsNil)
	e, err := environs.New(cfg)
	c.Assert(err, gc.IsNil)
	c.Assert(func() { e.Storage() }, gc.PanicMatches, "environment .* is not prepared")
}

func (OpenSuite) TestPrepare(c *gc.C) {
	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(
		testing.Attrs{
			"state-server": false,
			"name":         "erewhemos",
		},
	))
	c.Assert(err, gc.IsNil)
	store := configstore.NewMem()
	env, err := environs.Prepare(cfg, store)
	c.Assert(err, gc.IsNil)
	// Check we can access storage ok, which implies the environment has been prepared.
	c.Assert(env.Storage(), gc.NotNil)

	// Check that the environment info file was correctly created.
	info, err := store.ReadInfo("erewhemos")
	c.Assert(err, gc.IsNil)
	c.Assert(info.Initialized(), jc.IsTrue)
	c.Assert(info.BootstrapConfig(), gc.DeepEquals, env.Config().AllAttrs())

	// Check we can call Prepare again.
	env, err = environs.Prepare(cfg, store)
	c.Assert(err, gc.IsNil)
	c.Assert(env.Name(), gc.Equals, "erewhemos")
	c.Assert(env.Storage(), gc.NotNil)
}

func (OpenSuite) TestDestroy(c *gc.C) {
	cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(
		testing.Attrs{
			"state-server": false,
			"name":         "erewhemos",
		},
	))
	c.Assert(err, gc.IsNil)

	store := configstore.NewMem()
	// Prepare the environment and sanity-check that
	// the config storage info has been made.
	e, err := environs.Prepare(cfg, store)
	c.Assert(err, gc.IsNil)
	_, err = store.ReadInfo(e.Name())
	c.Assert(err, gc.IsNil)

	err = environs.Destroy(e, store)
	c.Assert(err, gc.IsNil)

	// Check that the environment has actually been destroyed
	// and that the config info has been destroyed too.
	c.Assert(func() { e.Storage() }, gc.PanicMatches, "environment.* is not prepared")
	_, err = store.ReadInfo(e.Name())
	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
}

func (OpenSuite) TestNewFromAttrs(c *gc.C) {
	e, err := environs.NewFromAttrs(dummy.SampleConfig().Merge(
		testing.Attrs{
			"state-server": false,
			"name":         "erewhemos",
		},
	))
	c.Assert(err, gc.IsNil)
	c.Assert(func() { e.Storage() }, gc.PanicMatches, "environment .* is not prepared")
}

const checkEnv = `
environments:
    test:
        type: dummy
        state-server: false
        authorized-keys: i-am-a-key
`

type checkEnvironmentSuite struct{}

var _ = gc.Suite(&checkEnvironmentSuite{})

func (s *checkEnvironmentSuite) TearDownTest(c *gc.C) {
	dummy.Reset()
}

func (s *checkEnvironmentSuite) TestCheckEnvironment(c *gc.C) {
	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()

	environ, err := environs.PrepareFromName("test", configstore.NewMem())
	c.Assert(err, gc.IsNil)

	// VerifyStorage is sufficient for our tests and much simpler
	// than Bootstrap which calls it.
	stor := environ.Storage()
	err = environs.VerifyStorage(stor)
	c.Assert(err, gc.IsNil)
	err = environs.CheckEnvironment(environ)
	c.Assert(err, gc.IsNil)
}

func (s *checkEnvironmentSuite) TestCheckEnvironmentFileNotFound(c *gc.C) {
	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()

	environ, err := environs.PrepareFromName("test", configstore.NewMem())
	c.Assert(err, gc.IsNil)

	// VerifyStorage is sufficient for our tests and much simpler
	// than Bootstrap which calls it.
	stor := environ.Storage()
	err = environs.VerifyStorage(stor)
	c.Assert(err, gc.IsNil)

	// When the bootstrap-verify file does not exist, it still believes
	// the environment is a juju-core one because earlier versions
	// did not create that file.
	err = stor.Remove("bootstrap-verify")
	c.Assert(err, gc.IsNil)
	err = environs.CheckEnvironment(environ)
	c.Assert(err, gc.IsNil)
}

func (s *checkEnvironmentSuite) TestCheckEnvironmentGetFails(c *gc.C) {
	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()

	environ, err := environs.PrepareFromName("test", configstore.NewMem())
	c.Assert(err, gc.IsNil)

	// VerifyStorage is sufficient for our tests and much simpler
	// than Bootstrap which calls it.
	stor := environ.Storage()
	err = environs.VerifyStorage(stor)
	c.Assert(err, gc.IsNil)

	// When fetching the verification file from storage fails,
	// we get an InvalidEnvironmentError.
	someError := errors.Unauthorizedf("you shall not pass")
	dummy.Poison(stor, "bootstrap-verify", someError)
	err = environs.CheckEnvironment(environ)
	c.Assert(err, gc.Equals, someError)
}

func (s *checkEnvironmentSuite) TestCheckEnvironmentBadContent(c *gc.C) {
	defer testing.MakeFakeHome(c, checkEnv, "existing").Restore()

	environ, err := environs.PrepareFromName("test", configstore.NewMem())
	c.Assert(err, gc.IsNil)

	// We mock a bad (eg. from a Python-juju environment) bootstrap-verify.
	stor := environ.Storage()
	content := "bad verification content"
	reader := strings.NewReader(content)
	err = stor.Put("bootstrap-verify", reader, int64(len(content)))
	c.Assert(err, gc.IsNil)

	// When the bootstrap-verify file contains unexpected content,
	// we get an InvalidEnvironmentError.
	err = environs.CheckEnvironment(environ)
	c.Assert(err, gc.Equals, environs.InvalidEnvironmentError)
}
<|endoftext|>