<commit_before>package isolated

import (
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
	"code.cloudfoundry.org/cli/integration/helpers"
	"code.cloudfoundry.org/cli/integration/helpers/fakeservicebroker"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("update-service command", func() {
	Describe("help", func() {
		When("--help flag is set", func() {
			It("displays command usage to output", func() {
				session := helpers.CF("update-service", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say(`\s+update-service - Update a service instance`))
				Eventually(session).Should(Say(`USAGE:`))
				Eventually(session).Should(Say(`\s+cf update-service SERVICE_INSTANCE \[-p NEW_PLAN\] \[-c PARAMETERS_AS_JSON\] \[-t TAGS\] \[--upgrade\]`))
				Eventually(session).Should(Say(`\s+Optionally provide service-specific configuration parameters in a valid JSON object in-line:`))
				Eventually(session).Should(Say(`\s+cf update-service SERVICE_INSTANCE -c '{\"name\":\"value\",\"name\":\"value\"}'`))
				Eventually(session).Should(Say(`\s+Optionally provide a file containing service-specific configuration parameters in a valid JSON object\.`))
				Eventually(session).Should(Say(`\s+The path to the parameters file can be an absolute or relative path to a file:`))
				Eventually(session).Should(Say(`\s+cf update-service SERVICE_INSTANCE -c PATH_TO_FILE`))
				Eventually(session).Should(Say(`\s+Example of valid JSON object:`))
				Eventually(session).Should(Say(`\s+{`))
				Eventually(session).Should(Say(`\s+\"cluster_nodes\": {`))
				Eventually(session).Should(Say(`\s+\"count\": 5,`))
				Eventually(session).Should(Say(`\s+\"memory_mb\": 1024`))
				Eventually(session).Should(Say(`\s+}`))
				Eventually(session).Should(Say(`\s+}`))
				Eventually(session).Should(Say(`\s+ Optionally provide a list of comma-delimited tags that will be written to the VCAP_SERVICES environment variable for any bound applications.`))
				Eventually(session).Should(Say(`EXAMPLES:`))
				Eventually(session).Should(Say(`\s+cf update-service mydb -p gold`))
				Eventually(session).Should(Say(`\s+cf update-service mydb -c '{\"ram_gb\":4}'`))
				Eventually(session).Should(Say(`\s+cf update-service mydb -c ~/workspace/tmp/instance_config.json`))
				Eventually(session).Should(Say(`\s+cf update-service mydb -t "list, of, tags"`))
				Eventually(session).Should(Say(`\s+cf update-service mydb --upgrade`))
				Eventually(session).Should(Say(`OPTIONS:`))
				Eventually(session).Should(Say(`\s+-c\s+Valid JSON object containing service-specific configuration parameters, provided either in-line or in a file\. For a list of supported configuration parameters, see documentation for the particular service offering\.`))
				Eventually(session).Should(Say(`\s+-p\s+Change service plan for a service instance`))
				Eventually(session).Should(Say(`\s+-t\s+User provided tags`))
				Eventually(session).Should(Say(`\s+-u\s+Upgrade the service instance to the latest version of the service plan available. This flag is in EXPERIMENTAL stage and may change without notice. It cannot be combined with other flags.`))
				Eventually(session).Should(Say(`SEE ALSO:`))
				Eventually(session).Should(Say(`\s+rename-service, services, update-user-provided-service`))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("the environment is not setup correctly", func() {
		BeforeEach(func() {
			helpers.SkipIfVersionLessThan(ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2)
		})

		It("fails with the appropriate errors", func() {
			// the upgrade flag is passed here to exercise a particular code path before refactoring
			helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "update-service", "foo", "--upgrade")
		})
	})

	When("an api is targeted, the user is logged in, and an org and space are targeted", func() {
		var (
			orgName string
		)

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			var spaceName = helpers.NewSpaceName()
			helpers.SetupCF(orgName, spaceName)
		})

		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		When("there are no service instances", func() {
			When("upgrading", func() {
				BeforeEach(func() {
					helpers.SkipIfVersionLessThan(ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2)
				})

				It("displays an informative error before prompting and exits 1", func() {
					session := helpers.CF("update-service", "non-existent-service", "--upgrade")
					Eventually(session.Err).Should(Say("Service instance non-existent-service not found"))
					Eventually(session).Should(Exit(1))
				})
			})
		})

		When("providing other arguments while upgrading", func() {
			It("displays an informative error message and exits 1", func() {
				session := helpers.CF("update-service", "irrelevant", "--upgrade", "-c", "{\"hello\": \"world\"}")
				Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: --upgrade, -t, -c, -p"))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Exit(1))
			})
		})

		When("there is a service instance", func() {
			var (
				broker              *fakeservicebroker.FakeServiceBroker
				serviceInstanceName string
				username            string
			)

			BeforeEach(func() {
				broker = fakeservicebroker.New().Register()
				Eventually(helpers.CF("enable-service-access", broker.ServiceName())).Should(Exit(0))

				serviceInstanceName = helpers.PrefixedRandomName("SI")
				Eventually(helpers.CF("create-service", broker.ServiceName(), broker.ServicePlanName(), serviceInstanceName)).Should(Exit(0))

				username, _ = helpers.GetCredentials()
			})

			AfterEach(func() {
				Eventually(helpers.CF("delete-service", serviceInstanceName, "-f")).Should(Exit(0))
				broker.Destroy()
			})

			When("updating to a service plan that does not exist", func() {
				It("displays an informative error message, exits 1", func() {
					session := helpers.CF("update-service", serviceInstanceName, "-p", "non-existing-service-plan")
					Eventually(session).Should(Say("Plan does not exist for the %s service", broker.ServiceName()))
					Eventually(session).Should(Exit(1))
				})
			})

			When("updating to the same service plan (no-op)", func() {
				It("displays an informative success message, exits 0", func() {
					session := helpers.CF("update-service", serviceInstanceName, "-p", broker.ServicePlanName())
					Eventually(session).Should(Say("Updating service instance %s as %s...", serviceInstanceName, username))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Say("No changes were made"))
					Eventually(session).Should(Exit(0))
				})
			})

			When("upgrading", func() {
				var buffer *Buffer

				BeforeEach(func() {
					buffer = NewBuffer()
				})

				When("the user provides --upgrade in an unsupported CAPI version", func() {
					BeforeEach(func() {
						helpers.SkipIfVersionAtLeast(ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2)
					})

					It("should report that the version of CAPI is too low", func() {
						session := helpers.CF("update-service", serviceInstanceName, "--upgrade")
						Eventually(session.Err).Should(Say(`Option '--upgrade' requires CF API version %s or higher. Your target is 2\.\d+\.\d+`, ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2))
						Eventually(session).Should(Exit(1))
					})
				})

				When("when CAPI supports service instance maintenance_info updates", func() {
					BeforeEach(func() {
						helpers.SkipIfVersionLessThan(ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2)
					})

					When("cancelling the update", func() {
						BeforeEach(func() {
							_, err := buffer.Write([]byte("n\n"))
							Expect(err).ToNot(HaveOccurred())
						})

						It("does not proceed", func() {
							session := helpers.CFWithStdin(buffer, "update-service", serviceInstanceName, "--upgrade")
							Eventually(session).Should(Say("You are about to update %s", serviceInstanceName))
							Eventually(session).Should(Say("Warning: This operation may be long running and will block further operations on the service until complete."))
							Eventually(session).Should(Say("Really update service %s\\? \\[yN\\]:", serviceInstanceName))
							Eventually(session).Should(Say("Update cancelled"))
							Eventually(session).Should(Exit(0))
						})
					})

					When("proceeding with the update", func() {
						BeforeEach(func() {
							_, err := buffer.Write([]byte("y\n"))
							Expect(err).ToNot(HaveOccurred())
						})

						It("updates the service", func() {
							session := helpers.CFWithStdin(buffer, "update-service", serviceInstanceName, "--upgrade")

							By("displaying an informative message")
							Eventually(session).Should(Say("You are about to update %s", serviceInstanceName))
							Eventually(session).Should(Say("Warning: This operation may be long running and will block further operations on the service until complete."))
							Eventually(session).Should(Say("Really update service %s\\? \\[yN\\]:", serviceInstanceName))
							Eventually(session).Should(Exit(0))

							By("requesting an upgrade from the platform")
							session = helpers.CF("service", serviceInstanceName)
							Eventually(session).Should(Say("status:\\s+update succeeded"))
						})
					})
				})
			})
		})
	})
})
<commit_msg>Add integration test for no upgrade available scenario.<commit_after>package isolated

import (
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
	"code.cloudfoundry.org/cli/integration/helpers"
	"code.cloudfoundry.org/cli/integration/helpers/fakeservicebroker"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("update-service command", func() {
	Describe("help", func() {
		When("--help flag is set", func() {
			It("displays command usage to output", func() {
				session := helpers.CF("update-service", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say(`\s+update-service - Update a service instance`))
				Eventually(session).Should(Say(`USAGE:`))
				Eventually(session).Should(Say(`\s+cf update-service SERVICE_INSTANCE \[-p NEW_PLAN\] \[-c PARAMETERS_AS_JSON\] \[-t TAGS\] \[--upgrade\]`))
				Eventually(session).Should(Say(`\s+Optionally provide service-specific configuration parameters in a valid JSON object in-line:`))
				Eventually(session).Should(Say(`\s+cf update-service SERVICE_INSTANCE -c '{\"name\":\"value\",\"name\":\"value\"}'`))
				Eventually(session).Should(Say(`\s+Optionally provide a file containing service-specific configuration parameters in a valid JSON object\.`))
				Eventually(session).Should(Say(`\s+The path to the parameters file can be an absolute or relative path to a file:`))
				Eventually(session).Should(Say(`\s+cf update-service SERVICE_INSTANCE -c PATH_TO_FILE`))
				Eventually(session).Should(Say(`\s+Example of valid JSON object:`))
				Eventually(session).Should(Say(`\s+{`))
				Eventually(session).Should(Say(`\s+\"cluster_nodes\": {`))
				Eventually(session).Should(Say(`\s+\"count\": 5,`))
				Eventually(session).Should(Say(`\s+\"memory_mb\": 1024`))
				Eventually(session).Should(Say(`\s+}`))
				Eventually(session).Should(Say(`\s+}`))
				Eventually(session).Should(Say(`\s+ Optionally provide a list of comma-delimited tags that will be written to the VCAP_SERVICES environment variable for any bound applications.`))
				Eventually(session).Should(Say(`EXAMPLES:`))
				Eventually(session).Should(Say(`\s+cf update-service mydb -p gold`))
				Eventually(session).Should(Say(`\s+cf update-service mydb -c '{\"ram_gb\":4}'`))
				Eventually(session).Should(Say(`\s+cf update-service mydb -c ~/workspace/tmp/instance_config.json`))
				Eventually(session).Should(Say(`\s+cf update-service mydb -t "list, of, tags"`))
				Eventually(session).Should(Say(`\s+cf update-service mydb --upgrade`))
				Eventually(session).Should(Say(`OPTIONS:`))
				Eventually(session).Should(Say(`\s+-c\s+Valid JSON object containing service-specific configuration parameters, provided either in-line or in a file\. For a list of supported configuration parameters, see documentation for the particular service offering\.`))
				Eventually(session).Should(Say(`\s+-p\s+Change service plan for a service instance`))
				Eventually(session).Should(Say(`\s+-t\s+User provided tags`))
				Eventually(session).Should(Say(`\s+-u\s+Upgrade the service instance to the latest version of the service plan available. This flag is in EXPERIMENTAL stage and may change without notice. It cannot be combined with other flags.`))
				Eventually(session).Should(Say(`SEE ALSO:`))
				Eventually(session).Should(Say(`\s+rename-service, services, update-user-provided-service`))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("the environment is not setup correctly", func() {
		BeforeEach(func() {
			helpers.SkipIfVersionLessThan(ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2)
		})

		It("fails with the appropriate errors", func() {
			// the upgrade flag is passed here to exercise a particular code path before refactoring
			helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "update-service", "foo", "--upgrade")
		})
	})

	When("an api is targeted, the user is logged in, and an org and space are targeted", func() {
		var (
			orgName string
		)

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			var spaceName = helpers.NewSpaceName()
			helpers.SetupCF(orgName, spaceName)
		})

		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		When("there are no service instances", func() {
			When("upgrading", func() {
				BeforeEach(func() {
					helpers.SkipIfVersionLessThan(ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2)
				})

				It("displays an informative error before prompting and exits 1", func() {
					session := helpers.CF("update-service", "non-existent-service", "--upgrade")
					Eventually(session.Err).Should(Say("Service instance non-existent-service not found"))
					Eventually(session).Should(Exit(1))
				})
			})
		})

		When("providing other arguments while upgrading", func() {
			It("displays an informative error message and exits 1", func() {
				session := helpers.CF("update-service", "irrelevant", "--upgrade", "-c", "{\"hello\": \"world\"}")
				Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: --upgrade, -t, -c, -p"))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Exit(1))
			})
		})

		When("there is a service instance", func() {
			var (
				broker              *fakeservicebroker.FakeServiceBroker
				serviceInstanceName string
				username            string
			)

			BeforeEach(func() {
				broker = fakeservicebroker.New().Register()
				Eventually(helpers.CF("enable-service-access", broker.ServiceName())).Should(Exit(0))

				serviceInstanceName = helpers.PrefixedRandomName("SI")
				Eventually(helpers.CF("create-service", broker.ServiceName(), broker.ServicePlanName(), serviceInstanceName)).Should(Exit(0))

				username, _ = helpers.GetCredentials()
			})

			AfterEach(func() {
				Eventually(helpers.CF("delete-service", serviceInstanceName, "-f")).Should(Exit(0))
				broker.Destroy()
			})

			When("updating to a service plan that does not exist", func() {
				It("displays an informative error message, exits 1", func() {
					session := helpers.CF("update-service", serviceInstanceName, "-p", "non-existing-service-plan")
					Eventually(session).Should(Say("Plan does not exist for the %s service", broker.ServiceName()))
					Eventually(session).Should(Exit(1))
				})
			})

			When("updating to the same service plan (no-op)", func() {
				It("displays an informative success message, exits 0", func() {
					session := helpers.CF("update-service", serviceInstanceName, "-p", broker.ServicePlanName())
					Eventually(session).Should(Say("Updating service instance %s as %s...", serviceInstanceName, username))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Say("No changes were made"))
					Eventually(session).Should(Exit(0))
				})
			})

			When("upgrading", func() {
				var buffer *Buffer

				BeforeEach(func() {
					buffer = NewBuffer()
				})

				When("the user provides --upgrade in an unsupported CAPI version", func() {
					BeforeEach(func() {
						helpers.SkipIfVersionAtLeast(ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2)
					})

					It("should report that the version of CAPI is too low", func() {
						session := helpers.CF("update-service", serviceInstanceName, "--upgrade")
						Eventually(session.Err).Should(Say(`Option '--upgrade' requires CF API version %s or higher. Your target is 2\.\d+\.\d+`, ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2))
						Eventually(session).Should(Exit(1))
					})
				})

				When("when CAPI supports service instance maintenance_info updates", func() {
					BeforeEach(func() {
						helpers.SkipIfVersionLessThan(ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2)
					})

					When("cancelling the update", func() {
						BeforeEach(func() {
							_, err := buffer.Write([]byte("n\n"))
							Expect(err).ToNot(HaveOccurred())
						})

						It("does not proceed", func() {
							session := helpers.CFWithStdin(buffer, "update-service", serviceInstanceName, "--upgrade")
							Eventually(session).Should(Say("You are about to update %s", serviceInstanceName))
							Eventually(session).Should(Say("Warning: This operation may be long running and will block further operations on the service until complete."))
							Eventually(session).Should(Say("Really update service %s\\? \\[yN\\]:", serviceInstanceName))
							Eventually(session).Should(Say("Update cancelled"))
							Eventually(session).Should(Exit(0))
						})
					})

					When("proceeding with the update", func() {
						BeforeEach(func() {
							_, err := buffer.Write([]byte("y\n"))
							Expect(err).ToNot(HaveOccurred())
						})

						When("upgrade is available", func() {
							BeforeEach(func() {
								broker.Services[0].Plans[0].MaintenanceInfo.Version = "9.1.2"
								broker.Update()
							})

							It("updates the service", func() {
								session := helpers.CFWithStdin(buffer, "update-service", serviceInstanceName, "--upgrade")

								By("displaying an informative message")
								Eventually(session).Should(Say("You are about to update %s", serviceInstanceName))
								Eventually(session).Should(Say("Warning: This operation may be long running and will block further operations on the service until complete."))
								Eventually(session).Should(Say("Really update service %s\\? \\[yN\\]:", serviceInstanceName))
								Eventually(session).Should(Exit(0))

								By("requesting an upgrade from the platform")
								session = helpers.CF("service", serviceInstanceName)
								Eventually(session).Should(Say("status:\\s+update succeeded"))
							})
						})

						When("no upgrade is available", func() {
							It("does not update the service and outputs informative message", func() {
								session := helpers.CFWithStdin(buffer, "update-service", serviceInstanceName, "--upgrade")

								Eventually(session).Should(Say("You are about to update %s", serviceInstanceName))
								Eventually(session).Should(Say("Warning: This operation may be long running and will block further operations on the service until complete."))
								Eventually(session).Should(Say("Really update service %s\\? \\[yN\\]:", serviceInstanceName))
								Eventually(session.Err).Should(Say("No upgrade is available."))
								Eventually(session.Err).Should(Say("TIP: To find out if upgrade is available run `cf service %s`.", serviceInstanceName))
								Eventually(session).Should(Exit(1))
							})
						})
					})
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>package gosmpp

import (
	"context"
	"fmt"
	"net"
	"testing"
	"time"

	"github.com/linxGnu/gosmpp/pdu"

	"github.com/stretchr/testify/require"
)

func TestTransmitter(t *testing.T) {
	t.Run("binding", func(t *testing.T) {
		auth := nextAuth()
		transmitter, err := NewTransmitterSession(NonTLSDialer, auth, TransmitSettings{
			WriteTimeout: time.Second,
			OnSubmitError: func(p pdu.PDU, err error) {
				t.Fatal(err)
			},
			OnRebindingError: func(err error) {
				t.Fatal(err)
			},
			OnClosed: func(state State) {
				fmt.Println(state)
			},
		}, 5*time.Second)
		require.Nil(t, err)
		require.NotNil(t, transmitter)
		defer func() {
			_ = transmitter.Close()
		}()

		require.Equal(t, "MelroseLabsSMSC", transmitter.Transmitter().SystemID())

		err = transmitter.Transmitter().Submit(newSubmitSM(auth.SystemID))
		require.Nil(t, err)

		time.Sleep(400 * time.Millisecond)

		transmitter.rebind()
		err = transmitter.Transmitter().Submit(newSubmitSM(auth.SystemID))
		require.Nil(t, err)
	})

	errorHandling := func(t *testing.T, trigger func(*transmitter)) {
		conn, err := net.Dial("tcp", "smscsim.melroselabs.com:2775")
		require.Nil(t, err)

		var tr transmitter

		c := NewConnection(conn)
		defer func() {
			_ = c.Close()

			// write on closed conn?
			n, err := tr.write([]byte{1, 2, 3})
			require.NotNil(t, err)
			require.Zero(t, n)
		}()

		// fake settings
		tr.conn = c
		tr.ctx, tr.cancel = context.WithCancel(context.Background())

		var count int
		tr.settings.OnClosed = func(state State) {
			count++
		}

		tr.settings.OnSubmitError = func(p pdu.PDU, err error) {
			require.NotNil(t, err)
			_, ok := p.(*pdu.CancelSM)
			require.True(t, ok)
		}
		tr.settings.WriteTimeout = 500 * time.Millisecond

		// do trigger
		trigger(&tr)

		time.Sleep(300 * time.Millisecond)
		require.NotZero(t, count)
	}

	t.Run("errorHandling1", func(t *testing.T) {
		errorHandling(t, func(tr *transmitter) {
			var p pdu.CancelSM
			tr.check(&p, 100, fmt.Errorf("fake error"))
		})
	})

	t.Run("errorHandling2", func(t *testing.T) {
		errorHandling(t, func(tr *transmitter) {
			var p pdu.CancelSM
			tr.check(&p, 0, fmt.Errorf("fake error"))
		})
	})

	t.Run("errorHandling3", func(t *testing.T) {
		errorHandling(t, func(tr *transmitter) {
			var p pdu.CancelSM
			tr.check(&p, 0, &net.DNSError{IsTemporary: false})
		})
	})
}
<commit_msg>Fix test race<commit_after>package gosmpp

import (
	"context"
	"fmt"
	"net"
	"sync/atomic"
	"testing"
	"time"

	"github.com/linxGnu/gosmpp/pdu"

	"github.com/stretchr/testify/require"
)

func TestTransmitter(t *testing.T) {
	t.Run("binding", func(t *testing.T) {
		auth := nextAuth()
		transmitter, err := NewTransmitterSession(NonTLSDialer, auth, TransmitSettings{
			WriteTimeout: time.Second,
			OnSubmitError: func(p pdu.PDU, err error) {
				t.Fatal(err)
			},
			OnRebindingError: func(err error) {
				t.Fatal(err)
			},
			OnClosed: func(state State) {
				fmt.Println(state)
			},
		}, 5*time.Second)
		require.Nil(t, err)
		require.NotNil(t, transmitter)
		defer func() {
			_ = transmitter.Close()
		}()

		require.Equal(t, "MelroseLabsSMSC", transmitter.Transmitter().SystemID())

		err = transmitter.Transmitter().Submit(newSubmitSM(auth.SystemID))
		require.Nil(t, err)

		time.Sleep(400 * time.Millisecond)

		transmitter.rebind()
		err = transmitter.Transmitter().Submit(newSubmitSM(auth.SystemID))
		require.Nil(t, err)
	})

	errorHandling := func(t *testing.T, trigger func(*transmitter)) {
		conn, err := net.Dial("tcp", "smscsim.melroselabs.com:2775")
		require.Nil(t, err)

		var tr transmitter

		c := NewConnection(conn)
		defer func() {
			_ = c.Close()

			// write on closed conn?
			n, err := tr.write([]byte{1, 2, 3})
			require.NotNil(t, err)
			require.Zero(t, n)
		}()

		// fake settings
		tr.conn = c
		tr.ctx, tr.cancel = context.WithCancel(context.Background())

		var count int32
		tr.settings.OnClosed = func(state State) {
			atomic.AddInt32(&count, 1)
		}

		tr.settings.OnSubmitError = func(p pdu.PDU, err error) {
			require.NotNil(t, err)
			_, ok := p.(*pdu.CancelSM)
			require.True(t, ok)
		}
		tr.settings.WriteTimeout = 500 * time.Millisecond

		// do trigger
		trigger(&tr)

		time.Sleep(300 * time.Millisecond)
		require.NotZero(t, atomic.LoadInt32(&count))
	}

	t.Run("errorHandling1", func(t *testing.T) {
		errorHandling(t, func(tr *transmitter) {
			var p pdu.CancelSM
			tr.check(&p, 100, fmt.Errorf("fake error"))
		})
	})

	t.Run("errorHandling2", func(t *testing.T) {
		errorHandling(t, func(tr *transmitter) {
			var p pdu.CancelSM
			tr.check(&p, 0, fmt.Errorf("fake error"))
		})
	})

	t.Run("errorHandling3", func(t *testing.T) {
		errorHandling(t, func(tr *transmitter) {
			var p pdu.CancelSM
			tr.check(&p, 0, &net.DNSError{IsTemporary: false})
		})
	})
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"github.com/lib/pq"
	"log"
	"os"
	"os/signal"
	"runtime/debug"
	"syscall"
	"time"
)

func WorkerExtractPgerror(err error) (*string, error) {
	pgerr, ok := err.(pq.PGError)
	if ok {
		msg := pgerr.Get('M')
		return &msg, nil
	}
	if err.Error() == "driver: bad connection" {
		msg := "could not connect to database"
		return &msg, nil
	}
	return nil, err
}

// WorkerCoerceType returns a coerced version of the raw
// database value in, which we get from scanning into
// interface{}s. We expect queries from the following
// Postgres types to result in the following return values:
// [Postgres] -> [Go: in] -> [Go: WorkerCoerceType'd]
// text          []byte      string
// ???
func WorkerCoerceType(in interface{}) interface{} {
	switch in := in.(type) {
	case []byte:
		return string(in)
	default:
		return in
	}
}

// WorkerQuery queries the pn db at pinDbUrl and updates the
// passed pin according to the results/errors. System errors
// are returned.
func WorkerQuery(p *Pin, pinDbUrl string) error {
	log.Printf("worker.query.start pin_id=%s", p.Id)
	applicationName := fmt.Sprintf("pgpin.pin.%s", p.Id)
	pinDbConn := fmt.Sprintf("%s?application_name=%s&statement_timeout=%d&connect_timeout=%d",
		pinDbUrl, applicationName, DataPinStatementTimeout/time.Millisecond, DataConnectTimeout/time.Millisecond)
	pinDb, err := sql.Open("postgres", pinDbConn)
	if err != nil {
		p.ResultsError, err = WorkerExtractPgerror(err)
		return err
	}
	resultsRows, err := pinDb.Query(p.Query)
	if err != nil {
		p.ResultsError, err = WorkerExtractPgerror(err)
		return err
	}
	defer resultsRows.Close()
	resultsFieldsData, err := resultsRows.Columns()
	if err != nil {
		p.ResultsError, err = WorkerExtractPgerror(err)
		return err
	}
	resultsRowsData := make([][]interface{}, 0)
	resultsRowsSeen := 0
	for resultsRows.Next() {
		resultsRowsSeen += 1
		if resultsRowsSeen > DataPinResultsRowsMax {
			message := "too many rows in query results"
			p.ResultsError = &message
			return nil
		}
		resultsRowData := make([]interface{}, len(resultsFieldsData))
		resultsRowPointers := make([]interface{}, len(resultsFieldsData))
		for i, _ := range resultsRowData {
			resultsRowPointers[i] = &resultsRowData[i]
		}
		err := resultsRows.Scan(resultsRowPointers...)
		if err != nil {
			p.ResultsError, err = WorkerExtractPgerror(err)
			return err
		}
		for i, _ := range resultsRowData {
			resultsRowData[i] = WorkerCoerceType(resultsRowData[i])
		}
		resultsRowsData = append(resultsRowsData, resultsRowData)
	}
	err = resultsRows.Err()
	if err != nil {
		p.ResultsError, err = WorkerExtractPgerror(err)
		return err
	}
	p.ResultsFields = MustNewPgJson(resultsFieldsData)
	p.ResultsRows = MustNewPgJson(resultsRowsData)
	log.Printf("worker.query.finish pin_id=%s", p.Id)
	return nil
}

// WorkerProcess performs a processes an update on the given
// pin, running its query against its db and updating the
// system database accordingly. User-caused errors are
// reflected in the updated pin record and will not cause a
// returned error. System-caused errors are returned.
func WorkerProcess(p *Pin) error {
	log.Printf("worker.process.start pin_id=%s", p.Id)
	pinDbUrl, err := DataPinDbUrl(p)
	if err != nil {
		return err
	}
	startedAt := time.Now()
	p.QueryStartedAt = &startedAt
	err = WorkerQuery(p, pinDbUrl)
	if err != nil {
		return err
	}
	finishedAt := time.Now()
	p.QueryFinishedAt = &finishedAt
	err = DataPinUpdate(p)
	if err != nil {
		return err
	}
	log.Printf("worker.process.finish pin_id=%s", p.Id)
	return nil
}

// WorkerTick processes 1 pending pin, if such a pin is
// available. It returns true iff a pin is processed.
func WorkerTick() (bool, error) {
	p, err := DataPinReserve()
	if err != nil {
		return false, err
	}
	if p != nil {
		log.Printf("worker.tick.found pin_id=%s", p.Id)
		err = WorkerProcess(p)
		if err != nil {
			return false, err
		}
		err = DataPinRelease(p)
		if err != nil {
			return false, err
		}
		return true, nil
	}
	return false, nil
}

// WorkerTrap returns a chanel that will be populated when
// an INT or TERM signals is received.
func WorkerTrap() chan bool {
	sig := make(chan os.Signal, 1)
	done := make(chan bool, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-sig
		log.Printf("worker.trap")
		done <- true
	}()
	return done
}

var WorkerCooloff = time.Millisecond*500

func WorkerCheckPanic() {
	err := recover()
	if err != nil {
		log.Printf("worker.panic: %s", err)
		log.Print(string(debug.Stack()))
		time.Sleep(WorkerCooloff)
	}
}

func WorkerHandleError(err error) {
	log.Printf("worker.error %s", err.Error())
	time.Sleep(WorkerCooloff)
}

func WorkerCheckExit(done chan bool) {
	select {
		case <-done:
			log.Printf("worker.exit")
			os.Exit(0)
		default:
	}
}

func WorkerLoop(done chan bool) {
	log.Printf("worker.loop")
	defer WorkerCheckPanic()
	processed, err := WorkerTick()
	if err != nil {
		WorkerHandleError(err)
	}
	WorkerCheckExit(done)
	if err == nil && !processed {
		time.Sleep(WorkerCooloff)
	}
}

func WorkerStart() {
	log.Printf("worker.start")
	DataStart()
	done := WorkerTrap()
	for {
		WorkerLoop(done)
	}
}
<commit_msg>Normalize worker tick logging<commit_after>package main

import (
	"database/sql"
	"fmt"
	"github.com/lib/pq"
	"log"
	"os"
	"os/signal"
	"runtime/debug"
	"syscall"
	"time"
)

func WorkerExtractPgerror(err error) (*string, error) {
	pgerr, ok := err.(pq.PGError)
	if ok {
		msg := pgerr.Get('M')
		return &msg, nil
	}
	if err.Error() == "driver: bad connection" {
		msg := "could not connect to database"
		return &msg, nil
	}
	return nil, err
}

// WorkerCoerceType returns a coerced version of the raw
// database value in, which we get from scanning into
// interface{}s. We expect queries from the following
// Postgres types to result in the following return values:
// [Postgres] -> [Go: in] -> [Go: WorkerCoerceType'd]
// text          []byte      string
// ???
func WorkerCoerceType(in interface{}) interface{} {
	switch in := in.(type) {
	case []byte:
		return string(in)
	default:
		return in
	}
}

// WorkerQuery queries the pn db at pinDbUrl and updates the
// passed pin according to the results/errors. System errors
// are returned.
func WorkerQuery(p *Pin, pinDbUrl string) error {
	log.Printf("worker.query.start pin_id=%s", p.Id)
	applicationName := fmt.Sprintf("pgpin.pin.%s", p.Id)
	pinDbConn := fmt.Sprintf("%s?application_name=%s&statement_timeout=%d&connect_timeout=%d",
		pinDbUrl, applicationName, DataPinStatementTimeout/time.Millisecond, DataConnectTimeout/time.Millisecond)
	pinDb, err := sql.Open("postgres", pinDbConn)
	if err != nil {
		p.ResultsError, err = WorkerExtractPgerror(err)
		return err
	}
	resultsRows, err := pinDb.Query(p.Query)
	if err != nil {
		p.ResultsError, err = WorkerExtractPgerror(err)
		return err
	}
	defer resultsRows.Close()
	resultsFieldsData, err := resultsRows.Columns()
	if err != nil {
		p.ResultsError, err = WorkerExtractPgerror(err)
		return err
	}
	resultsRowsData := make([][]interface{}, 0)
	resultsRowsSeen := 0
	for resultsRows.Next() {
		resultsRowsSeen += 1
		if resultsRowsSeen > DataPinResultsRowsMax {
			message := "too many rows in query results"
			p.ResultsError = &message
			return nil
		}
		resultsRowData := make([]interface{}, len(resultsFieldsData))
		resultsRowPointers := make([]interface{}, len(resultsFieldsData))
		for i, _ := range resultsRowData {
			resultsRowPointers[i] = &resultsRowData[i]
		}
		err := resultsRows.Scan(resultsRowPointers...)
		if err != nil {
			p.ResultsError, err = WorkerExtractPgerror(err)
			return err
		}
		for i, _ := range resultsRowData {
			resultsRowData[i] = WorkerCoerceType(resultsRowData[i])
		}
		resultsRowsData = append(resultsRowsData, resultsRowData)
	}
	err = resultsRows.Err()
	if err != nil {
		p.ResultsError, err = WorkerExtractPgerror(err)
		return err
	}
	p.ResultsFields = MustNewPgJson(resultsFieldsData)
	p.ResultsRows = MustNewPgJson(resultsRowsData)
	log.Printf("worker.query.finish pin_id=%s", p.Id)
	return nil
}

// WorkerProcess performs a processes an update on the given
// pin, running its query against its db and updating the
// system database accordingly. User-caused errors are
// reflected in the updated pin record and will not cause a
// returned error. System-caused errors are returned.
func WorkerProcess(p *Pin) error {
	log.Printf("worker.process.start pin_id=%s", p.Id)
	pinDbUrl, err := DataPinDbUrl(p)
	if err != nil {
		return err
	}
	startedAt := time.Now()
	p.QueryStartedAt = &startedAt
	err = WorkerQuery(p, pinDbUrl)
	if err != nil {
		return err
	}
	finishedAt := time.Now()
	p.QueryFinishedAt = &finishedAt
	err = DataPinUpdate(p)
	if err != nil {
		return err
	}
	log.Printf("worker.process.finish pin_id=%s", p.Id)
	return nil
}

// WorkerTick processes 1 pending pin, if such a pin is
// available. It returns true iff a pin is processed.
func WorkerTick() (bool, error) {
	log.Printf("worker.tick.start")
	p, err := DataPinReserve()
	if err != nil {
		return false, err
	}
	if p != nil {
		log.Printf("worker.tick.found pin_id=%s", p.Id)
		err = WorkerProcess(p)
		if err != nil {
			return false, err
		}
		err = DataPinRelease(p)
		if err != nil {
			return false, err
		}
		return true, nil
	}
	return false, nil
}

// WorkerTrap returns a chanel that will be populated when
// an INT or TERM signals is received.
func WorkerTrap() chan bool {
	sig := make(chan os.Signal, 1)
	done := make(chan bool, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-sig
		log.Printf("worker.trap")
		done <- true
	}()
	return done
}

var WorkerCooloff = time.Millisecond*500

func WorkerCheckPanic() {
	err := recover()
	if err != nil {
		log.Printf("worker.panic: %s", err)
		log.Print(string(debug.Stack()))
		time.Sleep(WorkerCooloff)
	}
}

func WorkerHandleError(err error) {
	log.Printf("worker.error %s", err.Error())
	time.Sleep(WorkerCooloff)
}

func WorkerCheckExit(done chan bool) {
	select {
		case <-done:
			log.Printf("worker.exit")
			os.Exit(0)
		default:
	}
}

func WorkerLoop(done chan bool) {
	defer WorkerCheckPanic()
	processed, err := WorkerTick()
	if err != nil {
		WorkerHandleError(err)
	}
	WorkerCheckExit(done)
	if err == nil && !processed {
		time.Sleep(WorkerCooloff)
	}
}

func WorkerStart() {
	log.Printf("worker.start")
	DataStart()
	done := WorkerTrap()
	for {
		WorkerLoop(done)
	}
}
<|endoftext|>


<commit_before>package unifi

import (
	"time"
	"strconv"
)

type Timestamp time.Time

func (t *Timestamp) UnmarshalJSON(b []byte) error {
	res, err := strconv.ParseInt(string(b), 0, 32)
	if err != nil {
		return err
	}
	*t = Timestamp(time.Unix(res, 0))
	return nil
}

func (t Timestamp) String() string {
	return time.Time(t).String()
}
<commit_msg>gofmt<commit_after>package unifi

import (
	"strconv"
	"time"
)

type Timestamp time.Time

func (t *Timestamp) UnmarshalJSON(b []byte) error {
	res, err := strconv.ParseInt(string(b), 0, 32)
	if err != nil {
		return err
	}
	*t = Timestamp(time.Unix(res, 0))
	return nil
}

func (t Timestamp) String() string {
	return time.Time(t).String()
}
<|endoftext|>


<commit_before>package iamy

import (
	"fmt"
	"sync"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
	"github.com/pkg/errors"
)

const NoSuchBucketPolicyErrCode = "NoSuchBucketPolicy"

func newRegionClientMap(s *session.Session) *regionClientMap {
	return &regionClientMap{
		clients: map[string]s3iface.S3API{},
		sess:    s,
		mutex:   &sync.Mutex{},
	}
}

type regionClientMap struct {
	sess    *session.Session
	clients map[string]s3iface.S3API
	mutex   *sync.Mutex
}

func (scm *regionClientMap) add(c *s3.S3) {
	scm.clients[*c.Config.Region] = c
}

func (scm *regionClientMap) getOrCreate(region string) s3iface.S3API {
	scm.mutex.Lock()
	if _, ok := scm.clients[region]; !ok {
		scm.clients[region] = s3.New(scm.sess, aws.NewConfig().WithRegion(region))
	}
	scm.mutex.Unlock()

	return scm.clients[region]
}

type s3Client struct {
	s3iface.S3API
	regionClients *regionClientMap
}

func newS3Client(s *session.Session) *s3Client {
	defaultClient := s3.New(s)
	clients := newRegionClientMap(s)
	clients.add(defaultClient)

	return &s3Client{
		S3API:         defaultClient,
		regionClients: clients,
	}
}

type bucket struct {
	name       string
	policyJson string
}

func (c *s3Client) withRegion(region string) s3iface.S3API {
	if region == "" {
		return c.S3API
	}

	return c.regionClients.getOrCreate(region)
}

func normaliseString(a *string) (b string) {
	if a != nil {
		b = *a
	}
	return
}

func (c *s3Client) populateBucket(b *bucket) error {
	r, err := c.GetBucketLocation(&s3.GetBucketLocationInput{Bucket: aws.String(b.name)})
	if err != nil {
		return err
	}

	region := normaliseString(r.LocationConstraint)
	b.policyJson, err = c.GetBucketPolicyDoc(b.name, region)

	return err
}

func (c *s3Client) listAllBuckets() ([]*bucket, error) {
	bucketListResp, err := c.ListBuckets(&s3.ListBucketsInput{})
	if err != nil {
		return nil, errors.Wrap(err, "Error while calling ListBuckets")
	}

	var wg sync.WaitGroup
	var oneOfTheErrorsDuringPopulation error
	buckets := []*bucket{}

	for _, rb := range bucketListResp.Buckets {
		b := bucket{name: *rb.Name}
		buckets = append(buckets, &b)

		wg.Add(1)
		go func() {
			defer wg.Done()
			err = c.populateBucket(&b)
			if err != nil {
				oneOfTheErrorsDuringPopulation = errors.New(fmt.Sprintf("Error while getting details for S3 bucket %s: %s", b.name, err))
			}
		}()
	}
	wg.Wait()

	if oneOfTheErrorsDuringPopulation != nil {
		return nil, oneOfTheErrorsDuringPopulation
	}

	return buckets, nil
}

func (c *s3Client) GetBucketPolicyDoc(name, region string) (string, error) {
	clientForRegion := c.withRegion(region)
	resp, err := clientForRegion.GetBucketPolicy(&s3.GetBucketPolicyInput{
		Bucket: aws.String(name),
	})
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == NoSuchBucketPolicyErrCode {
				return "", nil
			}
		}
		return "", fmt.Errorf("GetBucketPolicyDoc for %s: %s", name, err.Error())
	}

	return *resp.Policy, nil
}
<commit_msg>Normalise the bucket location<commit_after>package iamy

import (
	"fmt"
	"sync"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
	"github.com/pkg/errors"
)

const NoSuchBucketPolicyErrCode = "NoSuchBucketPolicy"

func newRegionClientMap(s *session.Session) *regionClientMap {
	return &regionClientMap{
		clients: map[string]s3iface.S3API{},
		sess:    s,
		mutex:   &sync.Mutex{},
	}
}

type regionClientMap struct {
	sess    *session.Session
	clients map[string]s3iface.S3API
	mutex   *sync.Mutex
}

func (scm *regionClientMap) add(c *s3.S3) {
	scm.clients[*c.Config.Region] = c
}

func (scm *regionClientMap) getOrCreate(region string) s3iface.S3API {
	scm.mutex.Lock()
	if _, ok := scm.clients[region]; !ok {
		scm.clients[region] = s3.New(scm.sess, aws.NewConfig().WithRegion(region))
	}
	scm.mutex.Unlock()

	return scm.clients[region]
}

type s3Client struct {
	s3iface.S3API
	regionClients *regionClientMap
}

func newS3Client(s *session.Session) *s3Client {
	defaultClient := s3.New(s)
	clients := newRegionClientMap(s)
	clients.add(defaultClient)

	return &s3Client{
		S3API:         defaultClient,
		regionClients: clients,
	}
}

type bucket struct {
	name       string
	policyJson string
}

func (c *s3Client) withRegion(region string) s3iface.S3API {
	if region == "" {
		return c.S3API
	}

	return c.regionClients.getOrCreate(region)
}

func normaliseString(a *string) (b string) {
	if a != nil {
		b = *a
	}
	return
}

func (c *s3Client) populateBucket(b *bucket) error {
	r, err := c.GetBucketLocation(&s3.GetBucketLocationInput{Bucket: aws.String(b.name)})
	if err != nil {
		return err
	}

	region := s3.NormalizeBucketLocation(normaliseString(r.LocationConstraint))
	b.policyJson, err = c.GetBucketPolicyDoc(b.name, region)

	return err
}

func (c *s3Client) listAllBuckets() ([]*bucket, error) {
	bucketListResp, err := c.ListBuckets(&s3.ListBucketsInput{})
	if err != nil {
		return nil, errors.Wrap(err, "Error while calling ListBuckets")
	}

	var wg sync.WaitGroup
	var oneOfTheErrorsDuringPopulation error
	buckets := []*bucket{}

	for _, rb := range bucketListResp.Buckets {
		b := bucket{name: *rb.Name}
		buckets = append(buckets, &b)

		wg.Add(1)
		go func() {
			defer wg.Done()
			err = c.populateBucket(&b)
			if err != nil {
				oneOfTheErrorsDuringPopulation = errors.New(fmt.Sprintf("Error while getting details for S3 bucket %s: %s", b.name, err))
			}
		}()
	}
	wg.Wait()

	if oneOfTheErrorsDuringPopulation != nil {
		return nil, oneOfTheErrorsDuringPopulation
	}

	return buckets, nil
}

func (c *s3Client) GetBucketPolicyDoc(name, region string) (string, error) {
	clientForRegion := c.withRegion(region)
	resp, err := clientForRegion.GetBucketPolicy(&s3.GetBucketPolicyInput{
		Bucket: aws.String(name),
	})
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == NoSuchBucketPolicyErrCode {
				return "", nil
			}
		}
		return "", fmt.Errorf("GetBucketPolicyDoc for %s: %s", name, err.Error())
	}

	return *resp.Policy, nil
}
<|endoftext|>


<commit_before>package twitter

import (
	"fmt"
	"net/http"

	"github.com/dghubble/sling"
)

// Tweet represents a Twitter Tweet, previously called a status.
// https://dev.twitter.com/overview/api/tweets
// Unused or deprecated fields not provided: Geo, Annotations
// TODO: Place
type Tweet struct {
	Contributors         []Contributor     `json:"contributors"`
	Coordinates          *Coordinates      `json:"coordinates"`
	CreatedAt            string            `json:"created_at"`
	CurrentUserRetweet   *TweetIdentifier  `json:"current_user_retweet"`
	Entities             *Entities         `json:"entities"`
	FavoriteCount        int               `json:"favorite_count"`
	Favorited            bool              `json:"favorited"`
	FilterLevel          string            `json:"filter_level"`
	ID                   int64             `json:"id"`
	IDStr                string            `json:"id_str"`
	InReplyToScreenName  string            `json:"in_reply_to_screen_name"`
	InReplyToStatusID    int64             `json:"in_reply_to_status_id"`
	InReplyToStatusIDStr string            `json:"in_reply_to_status_id_str"`
	InReplyToUserID      int64             `json:"in_reply_to_user_id"`
	InReplyToUserIDStr   string            `json:"in_reply_to_user_id_str"`
	Lang                 string            `json:"lang"`
	PossiblySensitive    bool              `json:"possibly_sensitive"`
	RetweetCount         int               `json:"retweet_count"`
	Retweeted            bool              `json:"retweeted"`
	RetweetedStatus      *Tweet            `json:"retweeted_status"`
	Source               string            `json:"source"`
	Scopes               map[string]string `json:"scopes"`
	Text                 string            `json:"text"`
	Truncated            bool              `json:"truncated"`
	User                 *User             `json:"user"`
	WithheldCopyright    bool              `json:"withheld_copyright"`
	WithheldInCountries  []string          `json:"withheld_in_countries"`
	WithheldScope        string            `json:"withheld_scope"`
	ExtendedEntities     *ExtendedEntity   `json:"extended_entities"`
	QuotedStatusID       int64             `json:"quoted_status_id"`
	QuotedStatusIDStr    string            `json:"quoted_status_id_str"`
	QuotedStatus         *Tweet            `json:"quoted_status"`
}

// Contributor represents a brief summary of a User identifiers.
type Contributor struct {
	ID         int64  `json:"id"`
	IDStr      string `json:"id_str"`
	ScreenName string `json:"screen_name"`
}

// Coordinates are pairs of longitude and latitude locations.
type Coordinates struct {
	Coordinates [2]float64 `json:"coordinates"`
	Type        string     `json:"type"`
}

// TweetIdentifier represents the id by which a Tweet can be identified.
type TweetIdentifier struct {
	ID    int64  `json:"id"`
	IDStr string `json:"id_str"`
}

// StatusService provides methods for accessing Twitter status API endpoints.
type StatusService struct {
	sling *sling.Sling
}

// newStatusService returns a new StatusService.
func newStatusService(sling *sling.Sling) *StatusService {
	return &StatusService{
		sling: sling.Path("statuses/"),
	}
}

// StatusShowParams are the parameters for StatusService.Show
type StatusShowParams struct {
	ID               int64 `url:"id,omitempty"`
	TrimUser         *bool `url:"trim_user,omitempty"`
	IncludeMyRetweet *bool `url:"include_my_retweet,omitempty"`
	IncludeEntities  *bool `url:"include_entities,omitempty"`
}

// Show returns the requested Tweet.
// https://dev.twitter.com/rest/reference/get/statuses/show/%3Aid
func (s *StatusService) Show(id int64, params *StatusShowParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusShowParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusLookupParams are the parameters for StatusService.Lookup
type StatusLookupParams struct {
	ID              []int64 `url:"id,omitempty,comma"`
	TrimUser        *bool   `url:"trim_user,omitempty"`
	IncludeEntities *bool   `url:"include_entities,omitempty"`
	Map             *bool   `url:"map,omitempty"`
}

// Lookup returns the requested Tweets as a slice. Combines ids from the
// required ids argument and from params.Id.
// https://dev.twitter.com/rest/reference/get/statuses/lookup
func (s *StatusService) Lookup(ids []int64, params *StatusLookupParams) ([]Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusLookupParams{}
	}
	params.ID = append(params.ID, ids...)
	tweets := new([]Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("lookup.json").QueryStruct(params).Receive(tweets, apiError)
	return *tweets, resp, relevantError(err, *apiError)
}

// StatusUpdateParams are the parameters for StatusService.Update
type StatusUpdateParams struct {
	Status             string   `url:"status,omitempty"`
	InReplyToStatusID  int64    `url:"in_reply_to_status_id,omitempty"`
	PossiblySensitive  *bool    `url:"possibly_sensitive,omitempty"`
	Lat                *float64 `url:"lat,omitempty"`
	Long               *float64 `url:"long,omitempty"`
	PlaceID            string   `url:"place_id,omitempty"`
	DisplayCoordinates *bool    `url:"display_coordinates,omitempty"`
	TrimUser           *bool    `url:"trim_user,omitempty"`
	MediaIds           []int64  `url:"media_ids,omitempty,comma"`
}

// Update updates the user's status, also known as Tweeting.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/update
func (s *StatusService) Update(status string, params *StatusUpdateParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusUpdateParams{}
	}
	params.Status = status
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Post("update.json").BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusRetweetParams are the parameters for StatusService.Retweet
type StatusRetweetParams struct {
	ID       int64 `url:"id,omitempty"`
	TrimUser *bool `url:"trim_user,omitempty"`
}

// Retweet retweets the Tweet with the given id and returns the original Tweet
// with embedded retweet details.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/retweet/%3Aid
func (s *StatusService) Retweet(id int64, params *StatusRetweetParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusRetweetParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("retweet/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusDestroyParams are the parameters for StatusService.Destroy
type StatusDestroyParams struct {
	ID       int64 `url:"id,omitempty"`
	TrimUser *bool `url:"trim_user,omitempty"`
}

// Destroy deletes the Tweet with the given id and returns it if successful.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/destroy/%3Aid
func (s *StatusService) Destroy(id int64, params *StatusDestroyParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusDestroyParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("destroy/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// OEmbedTweet represents a Tweet in oEmbed format.
type OEmbedTweet struct {
	URL          string `json:"url"`
	ProviderURL  string `json:"provider_url"`
	ProviderName string `json:"provider_name"`
	AuthorName   string `json:"author_name"`
	Version      string `json:"version"`
	AuthorURL    string `json:"author_url"`
	Type         string `json:"type"`
	HTML         string `json:"html"`
	Height       int64  `json:"height"`
	Width        int64  `json:"width"`
	CacheAge     string `json:"cache_age"`
}

// StatusOEmbedParams are the parameters for StatusService.OEmbed
type StatusOEmbedParams struct {
	ID         int64  `url:"id,omitempty"`
	URL        string `url:"url,omitempty"`
	Align      string `url:"align,omitempty"`
	MaxWidth   int64  `url:"maxwidth,omitempty"`
	HideMedia  *bool  `url:"hide_media,omitempty"`
	HideThread *bool  `url:"hide_media,omitempty"`
	OmitScript *bool  `url:"hide_media,omitempty"`
	WidgetType string `url:"widget_type,omitempty"`
	HideTweet  *bool  `url:"hide_tweet,omitempty"`
}

// OEmbed returns the requested Tweet in oEmbed format.
// https://dev.twitter.com/rest/reference/get/statuses/oembed
func (s *StatusService) OEmbed(params *StatusOEmbedParams) (*OEmbedTweet, *http.Response, error) {
	oEmbedTweet := new(OEmbedTweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("oembed.json").QueryStruct(params).Receive(oEmbedTweet, apiError)
	return oEmbedTweet, resp, relevantError(err, *apiError)
}
<commit_msg>Fix Tweet Scopes type, use interface{} value<commit_after>package twitter

import (
	"fmt"
	"net/http"

	"github.com/dghubble/sling"
)

// Tweet represents a Twitter Tweet, previously called a status.
// https://dev.twitter.com/overview/api/tweets
// Unused or deprecated fields not provided: Geo, Annotations
// TODO: Place
type Tweet struct {
	Contributors         []Contributor          `json:"contributors"`
	Coordinates          *Coordinates           `json:"coordinates"`
	CreatedAt            string                 `json:"created_at"`
	CurrentUserRetweet   *TweetIdentifier       `json:"current_user_retweet"`
	Entities             *Entities              `json:"entities"`
	FavoriteCount        int                    `json:"favorite_count"`
	Favorited            bool                   `json:"favorited"`
	FilterLevel          string                 `json:"filter_level"`
	ID                   int64                  `json:"id"`
	IDStr                string                 `json:"id_str"`
	InReplyToScreenName  string                 `json:"in_reply_to_screen_name"`
	InReplyToStatusID    int64                  `json:"in_reply_to_status_id"`
	InReplyToStatusIDStr string                 `json:"in_reply_to_status_id_str"`
	InReplyToUserID      int64                  `json:"in_reply_to_user_id"`
	InReplyToUserIDStr   string                 `json:"in_reply_to_user_id_str"`
	Lang                 string                 `json:"lang"`
	PossiblySensitive    bool                   `json:"possibly_sensitive"`
	RetweetCount         int                    `json:"retweet_count"`
	Retweeted            bool                   `json:"retweeted"`
	RetweetedStatus      *Tweet                 `json:"retweeted_status"`
	Source               string                 `json:"source"`
	Scopes               map[string]interface{} `json:"scopes"`
	Text                 string                 `json:"text"`
	Truncated            bool                   `json:"truncated"`
	User                 *User                  `json:"user"`
	WithheldCopyright    bool                   `json:"withheld_copyright"`
	WithheldInCountries  []string               `json:"withheld_in_countries"`
	WithheldScope        string                 `json:"withheld_scope"`
	ExtendedEntities     *ExtendedEntity        `json:"extended_entities"`
	QuotedStatusID       int64                  `json:"quoted_status_id"`
	QuotedStatusIDStr    string                 `json:"quoted_status_id_str"`
	QuotedStatus         *Tweet                 `json:"quoted_status"`
}

// Contributor represents a brief summary of a User identifiers.
type Contributor struct {
	ID         int64  `json:"id"`
	IDStr      string `json:"id_str"`
	ScreenName string `json:"screen_name"`
}

// Coordinates are pairs of longitude and latitude locations.
type Coordinates struct {
	Coordinates [2]float64 `json:"coordinates"`
	Type        string     `json:"type"`
}

// TweetIdentifier represents the id by which a Tweet can be identified.
type TweetIdentifier struct {
	ID    int64  `json:"id"`
	IDStr string `json:"id_str"`
}

// StatusService provides methods for accessing Twitter status API endpoints.
type StatusService struct {
	sling *sling.Sling
}

// newStatusService returns a new StatusService.
func newStatusService(sling *sling.Sling) *StatusService {
	return &StatusService{
		sling: sling.Path("statuses/"),
	}
}

// StatusShowParams are the parameters for StatusService.Show
type StatusShowParams struct {
	ID               int64 `url:"id,omitempty"`
	TrimUser         *bool `url:"trim_user,omitempty"`
	IncludeMyRetweet *bool `url:"include_my_retweet,omitempty"`
	IncludeEntities  *bool `url:"include_entities,omitempty"`
}

// Show returns the requested Tweet.
// https://dev.twitter.com/rest/reference/get/statuses/show/%3Aid
func (s *StatusService) Show(id int64, params *StatusShowParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusShowParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusLookupParams are the parameters for StatusService.Lookup
type StatusLookupParams struct {
	ID              []int64 `url:"id,omitempty,comma"`
	TrimUser        *bool   `url:"trim_user,omitempty"`
	IncludeEntities *bool   `url:"include_entities,omitempty"`
	Map             *bool   `url:"map,omitempty"`
}

// Lookup returns the requested Tweets as a slice. Combines ids from the
// required ids argument and from params.Id.
// https://dev.twitter.com/rest/reference/get/statuses/lookup
func (s *StatusService) Lookup(ids []int64, params *StatusLookupParams) ([]Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusLookupParams{}
	}
	params.ID = append(params.ID, ids...)
	tweets := new([]Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("lookup.json").QueryStruct(params).Receive(tweets, apiError)
	return *tweets, resp, relevantError(err, *apiError)
}

// StatusUpdateParams are the parameters for StatusService.Update
type StatusUpdateParams struct {
	Status             string   `url:"status,omitempty"`
	InReplyToStatusID  int64    `url:"in_reply_to_status_id,omitempty"`
	PossiblySensitive  *bool    `url:"possibly_sensitive,omitempty"`
	Lat                *float64 `url:"lat,omitempty"`
	Long               *float64 `url:"long,omitempty"`
	PlaceID            string   `url:"place_id,omitempty"`
	DisplayCoordinates *bool    `url:"display_coordinates,omitempty"`
	TrimUser           *bool    `url:"trim_user,omitempty"`
	MediaIds           []int64  `url:"media_ids,omitempty,comma"`
}

// Update updates the user's status, also known as Tweeting.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/update
func (s *StatusService) Update(status string, params *StatusUpdateParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusUpdateParams{}
	}
	params.Status = status
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Post("update.json").BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusRetweetParams are the parameters for StatusService.Retweet
type StatusRetweetParams struct {
	ID       int64 `url:"id,omitempty"`
	TrimUser *bool `url:"trim_user,omitempty"`
}

// Retweet retweets the Tweet with the given id and returns the original Tweet
// with embedded retweet details.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/retweet/%3Aid
func (s *StatusService) Retweet(id int64, params *StatusRetweetParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusRetweetParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("retweet/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusDestroyParams are the parameters for StatusService.Destroy
type StatusDestroyParams struct {
	ID       int64 `url:"id,omitempty"`
	TrimUser *bool `url:"trim_user,omitempty"`
}

// Destroy deletes the Tweet with the given id and returns it if successful.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/destroy/%3Aid
func (s *StatusService) Destroy(id int64, params *StatusDestroyParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusDestroyParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("destroy/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// OEmbedTweet represents a Tweet in oEmbed format.
type OEmbedTweet struct {
	URL          string `json:"url"`
	ProviderURL  string `json:"provider_url"`
	ProviderName string `json:"provider_name"`
	AuthorName   string `json:"author_name"`
	Version      string `json:"version"`
	AuthorURL    string `json:"author_url"`
	Type         string `json:"type"`
	HTML         string `json:"html"`
	Height       int64  `json:"height"`
	Width        int64  `json:"width"`
	CacheAge     string `json:"cache_age"`
}

// StatusOEmbedParams are the parameters for StatusService.OEmbed
type StatusOEmbedParams struct {
	ID         int64  `url:"id,omitempty"`
	URL        string `url:"url,omitempty"`
	Align      string `url:"align,omitempty"`
	MaxWidth   int64  `url:"maxwidth,omitempty"`
	HideMedia  *bool  `url:"hide_media,omitempty"`
	HideThread *bool  `url:"hide_media,omitempty"`
	OmitScript *bool  `url:"hide_media,omitempty"`
	WidgetType string `url:"widget_type,omitempty"`
	HideTweet  *bool  `url:"hide_tweet,omitempty"`
}

// OEmbed returns the requested Tweet in oEmbed format.
// https://dev.twitter.com/rest/reference/get/statuses/oembed
func (s *StatusService) OEmbed(params *StatusOEmbedParams) (*OEmbedTweet, *http.Response, error) {
	oEmbedTweet := new(OEmbedTweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("oembed.json").QueryStruct(params).Receive(oEmbedTweet, apiError)
	return oEmbedTweet, resp, relevantError(err, *apiError)
}
<|endoftext|>


<commit_before>// Copyright 2013 gopm authors.
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package doc

import (
	"bytes"
	"go/ast"
	"go/build"
	"go/doc"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/Unknwon/com"
)

type sliceWriter struct{ p *[]byte }

func (w sliceWriter) Write(p []byte) (int, error) {
	*w.p = append(*w.p, p...)
	return len(p), nil
}

func (w *walker) readDir(dir string) ([]os.FileInfo, error) {
	if dir != w.ImportPath {
		panic("unexpected")
	}
	fis := make([]os.FileInfo, 0, len(w.srcs))
	for _, src := range w.srcs {
		fis = append(fis, src)
	}
	return fis, nil
}

func (w *walker) openFile(path string) (io.ReadCloser, error) {
	if strings.HasPrefix(path, w.ImportPath+"/") {
		if src, ok := w.srcs[path[len(w.ImportPath)+1:]]; ok {
			return ioutil.NopCloser(bytes.NewReader(src.data)), nil
		}
	}
	panic("unexpected")
}

func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
	pkg := imports[path]
	if pkg == nil {
		// Guess the package name without importing it. Start with the last
		// element of the path.
		name := path[strings.LastIndex(path, "/")+1:]

		// Trim commonly used prefixes and suffixes containing illegal name
		// runes.
		name = strings.TrimSuffix(name, ".go")
		name = strings.TrimSuffix(name, "-go")
		name = strings.TrimPrefix(name, "go.")
		name = strings.TrimPrefix(name, "go-")
		name = strings.TrimPrefix(name, "biogo.")

		// It's also common for the last element of the path to contain an
		// extra "go" prefix, but not always. TODO: examine unresolved ids to
		// detect when trimming the "go" prefix is appropriate.

		pkg = ast.NewObj(ast.Pkg, name)
		pkg.Data = ast.NewScope(nil)
		imports[path] = pkg
	}
	return pkg, nil
}

// build gets imports from source files.
func (w *walker) build(srcs []*source, nod *Node) ([]string, error) {
	// Add source files to walker, I skipped references here.
	w.srcs = make(map[string]*source)
	for _, src := range srcs {
		w.srcs[src.name] = src
	}

	w.fset = token.NewFileSet()

	// Find the package and associated files.
	ctxt := build.Context{
		GOOS:          runtime.GOOS,
		GOARCH:        runtime.GOARCH,
		CgoEnabled:    true,
		JoinPath:      path.Join,
		IsAbsPath:     path.IsAbs,
		SplitPathList: func(list string) []string { return strings.Split(list, ":") },
		IsDir:         func(path string) bool { panic("unexpected") },
		HasSubdir:     func(root, dir string) (rel string, ok bool) { panic("unexpected") },
		ReadDir:       func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) },
		OpenFile:      func(path string) (r io.ReadCloser, err error) { return w.openFile(path) },
		Compiler:      "gc",
	}

	bpkg, err := ctxt.ImportDir(w.ImportPath, 0)
	// Continue if there are no Go source files; we still want the directory info.
	_, nogo := err.(*build.NoGoError)
	if err != nil {
		if nogo {
			err = nil
		} else {
			com.ColorLog("[WARN] Error occurs when check imports[ %s ]\n", err)
			return nil, nil
		}
	}

	// Parse the Go files

	files := make(map[string]*ast.File)
	for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) {
		file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
		if err != nil {
			//beego.Error("doc.walker.build():", err)
			continue
		}
		files[name] = file
	}

	w.ImportPath = strings.Replace(w.ImportPath, "\\", "/", -1)
	var imports []string
	for _, v := range bpkg.Imports {
		// Skip strandard library.
		if !IsGoRepoPath(v) &&
			(GetProjectPath(v) != GetProjectPath(w.ImportPath)) {
			imports = append(imports, v)
		}
	}

	apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil)

	mode := doc.Mode(0)
	if w.ImportPath == "builtin" {
		mode |= doc.AllDecls
	}

	pdoc := doc.New(apkg, w.ImportPath, mode)
	nod.Synopsis = Synopsis(pdoc.Doc)
	return imports, err
}

var badSynopsisPrefixes = []string{
	"Autogenerated by Thrift Compiler",
	"Automatically generated ",
	"Auto-generated by ",
	"Copyright ",
	"COPYRIGHT ",
	`THE SOFTWARE IS PROVIDED "AS IS"`,
	"TODO: ",
	"vim:",
}

// Synopsis extracts the first sentence from s. All runs of whitespace are
// replaced by a single space.
func Synopsis(s string) string {

	parts := strings.SplitN(s, "\n\n", 2)
	s = parts[0]

	var buf []byte
	const (
		other = iota
		period
		space
	)
	last := space
Loop:
	for i := 0; i < len(s); i++ {
		b := s[i]
		switch b {
		case ' ', '\t', '\r', '\n':
			switch last {
			case period:
				break Loop
			case other:
				buf = append(buf, ' ')
				last = space
			}
		case '.':
			last = period
			buf = append(buf, b)
		default:
			last = other
			buf = append(buf, b)
		}
	}

	// Ensure that synopsis fits an App Engine datastore text property.
	const m = 400
	if len(buf) > m {
		buf = buf[:m]
		if i := bytes.LastIndex(buf, []byte{' '}); i >= 0 {
			buf = buf[:i]
		}
		buf = append(buf, " ..."...)
	}

	s = string(buf)

	r, n := utf8.DecodeRuneInString(s)
	if n < 0 || unicode.IsPunct(r) || unicode.IsSymbol(r) {
		// ignore Markdown headings, editor settings, Go build constraints, and * in poorly formatted block comments.
		s = ""
	} else {
		for _, prefix := range badSynopsisPrefixes {
			if strings.HasPrefix(s, prefix) {
				s = ""
				break
			}
		}
	}

	return s
}
<commit_msg>Updated<commit_after>// Copyright 2013 gopm authors.
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package doc

import (
	"bytes"
	"go/ast"
	"go/build"
	"go/doc"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/Unknwon/com"
)

type sliceWriter struct{ p *[]byte }

func (w sliceWriter) Write(p []byte) (int, error) {
	*w.p = append(*w.p, p...)
	return len(p), nil
}

func (w *walker) readDir(dir string) ([]os.FileInfo, error) {
	if dir != w.ImportPath {
		panic("unexpected")
	}
	fis := make([]os.FileInfo, 0, len(w.srcs))
	for _, src := range w.srcs {
		fis = append(fis, src)
	}
	return fis, nil
}

func (w *walker) openFile(path string) (io.ReadCloser, error) {
	if strings.HasPrefix(path, w.ImportPath+"/") {
		if src, ok := w.srcs[path[len(w.ImportPath)+1:]]; ok {
			return ioutil.NopCloser(bytes.NewReader(src.data)), nil
		}
	}
	panic("unexpected")
}

func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
	pkg := imports[path]
	if pkg == nil {
		// Guess the package name without importing it. Start with the last
		// element of the path.
		name := path[strings.LastIndex(path, "/")+1:]

		// Trim commonly used prefixes and suffixes containing illegal name
		// runes.
		name = strings.TrimSuffix(name, ".go")
		name = strings.TrimSuffix(name, "-go")
		name = strings.TrimPrefix(name, "go.")
		name = strings.TrimPrefix(name, "go-")
		name = strings.TrimPrefix(name, "biogo.")

		// It's also common for the last element of the path to contain an
		// extra "go" prefix, but not always. TODO: examine unresolved ids to
		// detect when trimming the "go" prefix is appropriate.

		pkg = ast.NewObj(ast.Pkg, name)
		pkg.Data = ast.NewScope(nil)
		imports[path] = pkg
	}
	return pkg, nil
}

// build gets imports from source files.
func (w *walker) build(srcs []*source, nod *Node) ([]string, error) {
	// Add source files to walker, I skipped references here.
	w.srcs = make(map[string]*source)
	for _, src := range srcs {
		w.srcs[src.name] = src
	}

	w.fset = token.NewFileSet()

	// Find the package and associated files.
	ctxt := build.Context{
		GOOS:          runtime.GOOS,
		GOARCH:        runtime.GOARCH,
		CgoEnabled:    true,
		JoinPath:      path.Join,
		IsAbsPath:     path.IsAbs,
		SplitPathList: func(list string) []string { return strings.Split(list, ":") },
		IsDir:         func(path string) bool { panic("unexpected") },
		HasSubdir:     func(root, dir string) (rel string, ok bool) { panic("unexpected") },
		ReadDir:       func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) },
		OpenFile:      func(path string) (r io.ReadCloser, err error) { return w.openFile(path) },
		Compiler:      "gc",
	}

	bpkg, err := ctxt.ImportDir(w.ImportPath, 0)
	// Continue if there are no Go source files; we still want the directory info.
	_, nogo := err.(*build.NoGoError)
	if err != nil {
		if nogo {
			err = nil
		} else {
			com.ColorLog("[WARN] Error occurs when check imports[ %s ]\n", err)
			return nil, nil
		}
	}

	// Parse the Go files

	files := make(map[string]*ast.File)
	for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) {
		file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
		if err != nil {
			//beego.Error("doc.walker.build():", err)
			continue
		}
		files[name] = file
	}

	w.ImportPath = strings.Replace(w.ImportPath, "\\", "/", -1)
	var imports []string
	for _, v := range bpkg.Imports {
		// Skip strandard library.
		if !IsGoRepoPath(v) &&
			(GetProjectPath(v) != GetProjectPath(w.ImportPath)) {
			imports = append(imports, v)
		}
	}

	apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil)

	mode := doc.Mode(0)
	if w.ImportPath == "builtin" {
		mode |= doc.AllDecls
	}

	pdoc := doc.New(apkg, w.ImportPath, mode)
	nod.Synopsis = Synopsis(pdoc.Doc)
	if i := strings.Index(nod.Synopsis, "\n"); i > -1 {
		nod.Synopsis = nod.Synopsis[:i]
	}
	return imports, err
}

var badSynopsisPrefixes = []string{
	"Autogenerated by Thrift Compiler",
	"Automatically generated ",
	"Auto-generated by ",
	"Copyright ",
	"COPYRIGHT ",
	`THE SOFTWARE IS PROVIDED "AS IS"`,
	"TODO: ",
	"vim:",
}

// Synopsis extracts the first sentence from s. All runs of whitespace are
// replaced by a single space.
func Synopsis(s string) string {

	parts := strings.SplitN(s, "\n\n", 2)
	s = parts[0]

	var buf []byte
	const (
		other = iota
		period
		space
	)
	last := space
Loop:
	for i := 0; i < len(s); i++ {
		b := s[i]
		switch b {
		case ' ', '\t', '\r', '\n':
			switch last {
			case period:
				break Loop
			case other:
				buf = append(buf, ' ')
				last = space
			}
		case '.':
			last = period
			buf = append(buf, b)
		default:
			last = other
			buf = append(buf, b)
		}
	}

	// Ensure that synopsis fits an App Engine datastore text property.
	const m = 400
	if len(buf) > m {
		buf = buf[:m]
		if i := bytes.LastIndex(buf, []byte{' '}); i >= 0 {
			buf = buf[:i]
		}
		buf = append(buf, " ..."...)
	}

	s = string(buf)

	r, n := utf8.DecodeRuneInString(s)
	if n < 0 || unicode.IsPunct(r) || unicode.IsSymbol(r) {
		// ignore Markdown headings, editor settings, Go build constraints, and * in poorly formatted block comments.
		s = ""
	} else {
		for _, prefix := range badSynopsisPrefixes {
			if strings.HasPrefix(s, prefix) {
				s = ""
				break
			}
		}
	}

	return s
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"

	"github.com/grafana/grafana/pkg/api/dtos"
	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/middleware"
	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/services/alerting"
)

func ValidateOrgAlert(c *middleware.Context) {
	id := c.ParamsInt64(":alertId")
	query := models.GetAlertByIdQuery{Id: id}

	if err := bus.Dispatch(&query); err != nil {
		c.JsonApiErr(404, "Alert not found", nil)
		return
	}

	if c.OrgId != query.Result.OrgId {
		c.JsonApiErr(403, "You are not allowed to edit/view alert", nil)
		return
	}
}

func GetAlertStatesForDashboard(c *middleware.Context) Response {
	dashboardId := c.QueryInt64("dashboardId")

	if dashboardId == 0 {
		return ApiError(400, "Missing query parameter dashboardId", nil)
	}

	query := models.GetAlertStatesForDashboardQuery{
		OrgId:       c.OrgId,
		DashboardId: c.QueryInt64("dashboardId"),
	}

	if err := bus.Dispatch(&query); err != nil {
		return ApiError(500, "Failed to fetch alert states", err)
	}

	return Json(200, query.Result)
}

// GET /api/alerts
func GetAlerts(c *middleware.Context) Response {
	query := models.GetAlertsQuery{
		OrgId:       c.OrgId,
		DashboardId: c.QueryInt64("dashboardId"),
		PanelId:     c.QueryInt64("panelId"),
		Limit:       c.QueryInt64("limit"),
	}

	states := c.QueryStrings("state")
	if len(states) > 0 {
		query.State = states
	}

	if err := bus.Dispatch(&query); err != nil {
		return ApiError(500, "List alerts failed", err)
	}

	dashboardIds := make([]int64, 0)
	alertDTOs := make([]*dtos.AlertRule, 0)
	for _, alert := range query.Result {
		dashboardIds = append(dashboardIds, alert.DashboardId)
		alertDTOs = append(alertDTOs, &dtos.AlertRule{
			Id:             alert.Id,
			DashboardId:    alert.DashboardId,
			PanelId:        alert.PanelId,
			Name:           alert.Name,
			Message:        alert.Message,
			State:          alert.State,
			EvalDate:       alert.EvalDate,
			NewStateDate:   alert.NewStateDate,
			ExecutionError: alert.ExecutionError,
		})
	}

	dashboardsQuery := models.GetDashboardsQuery{
		DashboardIds: dashboardIds,
	}

	if len(alertDTOs) > 0 {
		if err := bus.Dispatch(&dashboardsQuery); err != nil {
			return ApiError(500, "List alerts failed", err)
		}
	}

	//TODO: should be possible to speed this up with lookup table
	for _, alert := range alertDTOs {
		for _, dash := range dashboardsQuery.Result {
			if alert.DashboardId == dash.Id {
				alert.DashbboardUri = "db/" + dash.Slug
			}
		}
	}

	return Json(200, alertDTOs)
}

// POST /api/alerts/test
func AlertTest(c *middleware.Context, dto dtos.AlertTestCommand) Response {
	if _, idErr := dto.Dashboard.Get("id").Int64(); idErr != nil {
		return ApiError(400, "The dashboard needs to be saved at least once before you can test an alert rule", nil)
	}

	backendCmd := alerting.AlertTestCommand{
		OrgId:     c.OrgId,
		Dashboard: dto.Dashboard,
		PanelId:   dto.PanelId,
	}

	if err := bus.Dispatch(&backendCmd); err != nil {
		if validationErr, ok := err.(alerting.ValidationError); ok {
			return ApiError(422, validationErr.Error(), nil)
		}
		return ApiError(500, "Failed to test rule", err)
	}

	res := backendCmd.Result

	dtoRes := &dtos.AlertTestResult{
		Firing:         res.Firing,
		ConditionEvals: res.ConditionEvals,
	}

	if res.Error != nil {
		dtoRes.Error = res.Error.Error()
	}

	for _, log := range res.Logs {
		dtoRes.Logs = append(dtoRes.Logs, &dtos.AlertTestResultLog{Message: log.Message, Data: log.Data})
	}
	for _, match := range res.EvalMatches {
		dtoRes.EvalMatches = append(dtoRes.EvalMatches, &dtos.EvalMatch{Metric: match.Metric, Value: match.Value})
	}

	dtoRes.TimeMs = fmt.Sprintf("%1.3fms", res.GetDurationMs())

	return Json(200, dtoRes)
}

// GET /api/alerts/:id
func GetAlert(c *middleware.Context) Response {
	id := c.ParamsInt64(":alertId")
	query := models.GetAlertByIdQuery{Id: id}

	if err := bus.Dispatch(&query); err != nil {
		return ApiError(500, "List alerts failed", err)
	}

	return Json(200, &query.Result)
}

// DEL /api/alerts/:id
func DelAlert(c *middleware.Context) Response {
	alertId := c.ParamsInt64(":alertId")

	if alertId == 0 {
		return ApiError(401, "Failed to parse alertid", nil)
	}

	cmd := models.DeleteAlertCommand{AlertId: alertId}

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "Failed to delete alert", err)
	}

	var resp = map[string]interface{}{"alertId": alertId}
	return Json(200, resp)
}

func GetAlertNotifications(c *middleware.Context) Response {
	query := &models.GetAllAlertNotificationsQuery{OrgId: c.OrgId}

	if err := bus.Dispatch(query); err != nil {
		return ApiError(500, "Failed to get alert notifications", err)
	}

	result := make([]*dtos.AlertNotification, 0)

	for _, notification := range query.Result {
		result = append(result, &dtos.AlertNotification{
			Id:        notification.Id,
			Name:      notification.Name,
			Type:      notification.Type,
			IsDefault: notification.IsDefault,
			Created:   notification.Created,
			Updated:   notification.Updated,
		})
	}

	return Json(200, result)
}

func GetAlertNotificationById(c *middleware.Context) Response {
	query := &models.GetAlertNotificationsQuery{
		OrgId: c.OrgId,
		Id:    c.ParamsInt64("notificationId"),
	}

	if err := bus.Dispatch(query); err != nil {
		return ApiError(500, "Failed to get alert notifications", err)
	}

	return Json(200, query.Result)
}

func CreateAlertNotification(c *middleware.Context, cmd models.CreateAlertNotificationCommand) Response {
	cmd.OrgId = c.OrgId

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "Failed to create alert notification", err)
	}

	return Json(200, cmd.Result)
}

func UpdateAlertNotification(c *middleware.Context, cmd models.UpdateAlertNotificationCommand) Response {
	cmd.OrgId = c.OrgId

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "Failed to update alert notification", err)
	}

	return Json(200, cmd.Result)
}

func DeleteAlertNotification(c *middleware.Context) Response {
	cmd := models.DeleteAlertNotificationCommand{
		OrgId: c.OrgId,
		Id:    c.ParamsInt64("notificationId"),
	}

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "Failed to delete alert notification", err)
	}

	return ApiSuccess("Notification deleted")
}

//POST /api/alert-notifications/test
func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) Response {
	cmd := &alerting.NotificationTestCommand{
		Name:     dto.Name,
		Type:     dto.Type,
		Settings: dto.Settings,
	}

	if err := bus.Dispatch(cmd); err != nil {
		return ApiError(500, "Failed to send alert notifications", err)
	}

	return ApiSuccess("Test notification sent")
}

//POST /api/alerts/:alertId/pause
func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response {
	alertId := c.ParamsInt64("alertId")
	cmd := models.PauseAlertCommand{
		OrgId:    c.OrgId,
		AlertIds: []int64{alertId},
		Paused:   dto.Paused,
	}

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "", err)
	}

	var response models.AlertStateType = models.AlertStatePending
	pausedState := "un paused"
	if cmd.Paused {
		response = models.AlertStatePaused
		pausedState = "paused"
	}

	result := map[string]interface{}{
		"alertId": alertId,
		"state":   response,
		"message": "alert " + pausedState,
	}

	return Json(200, result)
}

func existInSlice(slice []int64, value int64) bool {
	for _, v := range slice {
		if v == value {
			return true
		}
	}
	return false
}

//POST /api/alerts/pause
func PauseAlerts(c *middleware.Context, dto dtos.PauseAlertsCommand) Response {
	cmd := &models.GetAllAlertsQuery{}
	if err := bus.Dispatch(cmd); err != nil {
		return ApiError(500, "", err)
	}

	var alertsToUpdate []int64
	skipFilter := len(dto.DataSourceIds) == 0
	for _, alert := range cmd.Result {
		if skipFilter {
			alertsToUpdate = append(alertsToUpdate, alert.Id)
			continue
		}

		alert, err := alerting.NewRuleFromDBAlert(alert)
		if err != nil {
			return ApiError(500, "", err)
		}

		for _, v := range alert.Conditions {
			id, exist := v.GetDatsourceId()
			if exist && existInSlice(dto.DataSourceIds, *id) {
				alertsToUpdate = append(alertsToUpdate, alert.Id)
			}
		}
	}

	updateCmd := models.PauseAlertCommand{
		OrgId:    c.OrgId,
		AlertIds: alertsToUpdate,
		Paused:   dto.Paused,
	}

	if err := bus.Dispatch(&updateCmd); err != nil {
		return ApiError(500, "", err)
	}

	var response models.AlertStateType = models.AlertStatePending
	pausedState := "un paused"
	if updateCmd.Paused {
		response = models.AlertStatePaused
		pausedState = "paused"
	}

	result := map[string]interface{}{
		"state":          response,
		"message":        "alert " + pausedState,
		"alertsAffected": updateCmd.ResultCount,
	}

	return Json(200, result)
}
<commit_msg>style(api): extracts filter logic for mass pause<commit_after>package api

import (
	"fmt"

	"github.com/grafana/grafana/pkg/api/dtos"
	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/middleware"
	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/services/alerting"
)

func ValidateOrgAlert(c *middleware.Context) {
	id := c.ParamsInt64(":alertId")
	query := models.GetAlertByIdQuery{Id: id}

	if err := bus.Dispatch(&query); err != nil {
		c.JsonApiErr(404, "Alert not found", nil)
		return
	}

	if c.OrgId != query.Result.OrgId {
		c.JsonApiErr(403, "You are not allowed to edit/view alert", nil)
		return
	}
}

func GetAlertStatesForDashboard(c *middleware.Context) Response {
	dashboardId := c.QueryInt64("dashboardId")

	if dashboardId == 0 {
		return ApiError(400, "Missing query parameter dashboardId", nil)
	}

	query := models.GetAlertStatesForDashboardQuery{
		OrgId:       c.OrgId,
		DashboardId: c.QueryInt64("dashboardId"),
	}

	if err := bus.Dispatch(&query); err != nil {
		return ApiError(500, "Failed to fetch alert states", err)
	}

	return Json(200, query.Result)
}

// GET /api/alerts
func GetAlerts(c *middleware.Context) Response {
	query := models.GetAlertsQuery{
		OrgId:       c.OrgId,
		DashboardId: c.QueryInt64("dashboardId"),
		PanelId:     c.QueryInt64("panelId"),
		Limit:       c.QueryInt64("limit"),
	}

	states := c.QueryStrings("state")
	if len(states) > 0 {
		query.State = states
	}

	if err := bus.Dispatch(&query); err != nil {
		return ApiError(500, "List alerts failed", err)
	}

	dashboardIds := make([]int64, 0)
	alertDTOs := make([]*dtos.AlertRule, 0)
	for _, alert := range query.Result {
		dashboardIds = append(dashboardIds, alert.DashboardId)
		alertDTOs = append(alertDTOs, &dtos.AlertRule{
			Id:             alert.Id,
			DashboardId:    alert.DashboardId,
			PanelId:        alert.PanelId,
			Name:           alert.Name,
			Message:        alert.Message,
			State:          alert.State,
			EvalDate:       alert.EvalDate,
			NewStateDate:   alert.NewStateDate,
			ExecutionError: alert.ExecutionError,
		})
	}

	dashboardsQuery := models.GetDashboardsQuery{
		DashboardIds: dashboardIds,
	}

	if len(alertDTOs) > 0 {
		if err := bus.Dispatch(&dashboardsQuery); err != nil {
			return ApiError(500, "List alerts failed", err)
		}
	}

	//TODO: should be possible to speed this up with lookup table
	for _, alert := range alertDTOs {
		for _, dash := range dashboardsQuery.Result {
			if alert.DashboardId == dash.Id {
				alert.DashbboardUri = "db/" + dash.Slug
			}
		}
	}

	return Json(200, alertDTOs)
}

// POST /api/alerts/test
func AlertTest(c *middleware.Context, dto dtos.AlertTestCommand) Response {
	if _, idErr := dto.Dashboard.Get("id").Int64(); idErr != nil {
		return ApiError(400, "The dashboard needs to be saved at least once before you can test an alert rule", nil)
	}

	backendCmd := alerting.AlertTestCommand{
		OrgId:     c.OrgId,
		Dashboard: dto.Dashboard,
		PanelId:   dto.PanelId,
	}

	if err := bus.Dispatch(&backendCmd); err != nil {
		if validationErr, ok := err.(alerting.ValidationError); ok {
			return ApiError(422, validationErr.Error(), nil)
		}
		return ApiError(500, "Failed to test rule", err)
	}

	res := backendCmd.Result

	dtoRes := &dtos.AlertTestResult{
		Firing:         res.Firing,
		ConditionEvals: res.ConditionEvals,
	}

	if res.Error != nil {
		dtoRes.Error = res.Error.Error()
	}

	for _, log := range res.Logs {
		dtoRes.Logs = append(dtoRes.Logs, &dtos.AlertTestResultLog{Message: log.Message, Data: log.Data})
	}
	for _, match := range res.EvalMatches {
		dtoRes.EvalMatches = append(dtoRes.EvalMatches, &dtos.EvalMatch{Metric: match.Metric, Value: match.Value})
	}

	dtoRes.TimeMs = fmt.Sprintf("%1.3fms", res.GetDurationMs())

	return Json(200, dtoRes)
}

// GET /api/alerts/:id
func GetAlert(c *middleware.Context) Response {
	id := c.ParamsInt64(":alertId")
	query := models.GetAlertByIdQuery{Id: id}

	if err := bus.Dispatch(&query); err != nil {
		return ApiError(500, "List alerts failed", err)
	}

	return Json(200, &query.Result)
}

// DEL /api/alerts/:id
func DelAlert(c *middleware.Context) Response {
	alertId := c.ParamsInt64(":alertId")

	if alertId == 0 {
		return ApiError(401, "Failed to parse alertid", nil)
	}

	cmd := models.DeleteAlertCommand{AlertId: alertId}

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "Failed to delete alert", err)
	}

	var resp = map[string]interface{}{"alertId": alertId}
	return Json(200, resp)
}

func GetAlertNotifications(c *middleware.Context) Response {
	query := &models.GetAllAlertNotificationsQuery{OrgId: c.OrgId}

	if err := bus.Dispatch(query); err != nil {
		return ApiError(500, "Failed to get alert notifications", err)
	}

	result := make([]*dtos.AlertNotification, 0)

	for _, notification := range query.Result {
		result = append(result, &dtos.AlertNotification{
			Id:        notification.Id,
			Name:      notification.Name,
			Type:      notification.Type,
			IsDefault: notification.IsDefault,
			Created:   notification.Created,
			Updated:   notification.Updated,
		})
	}

	return Json(200, result)
}

func GetAlertNotificationById(c *middleware.Context) Response {
	query := &models.GetAlertNotificationsQuery{
		OrgId: c.OrgId,
		Id:    c.ParamsInt64("notificationId"),
	}

	if err := bus.Dispatch(query); err != nil {
		return ApiError(500, "Failed to get alert notifications", err)
	}

	return Json(200, query.Result)
}

func CreateAlertNotification(c *middleware.Context, cmd models.CreateAlertNotificationCommand) Response {
	cmd.OrgId = c.OrgId

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "Failed to create alert notification", err)
	}

	return Json(200, cmd.Result)
}

func UpdateAlertNotification(c *middleware.Context, cmd models.UpdateAlertNotificationCommand) Response {
	cmd.OrgId = c.OrgId

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "Failed to update alert notification", err)
	}

	return Json(200, cmd.Result)
}

func DeleteAlertNotification(c *middleware.Context) Response {
	cmd := models.DeleteAlertNotificationCommand{
		OrgId: c.OrgId,
		Id:    c.ParamsInt64("notificationId"),
	}

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "Failed to delete alert notification", err)
	}

	return ApiSuccess("Notification deleted")
}

//POST /api/alert-notifications/test
func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) Response {
	cmd := &alerting.NotificationTestCommand{
		Name:     dto.Name,
		Type:     dto.Type,
		Settings: dto.Settings,
	}

	if err := bus.Dispatch(cmd); err != nil {
		return ApiError(500, "Failed to send alert notifications", err)
	}

	return ApiSuccess("Test notification sent")
}

//POST /api/alerts/:alertId/pause
func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response {
	alertId := c.ParamsInt64("alertId")
	cmd := models.PauseAlertCommand{
		OrgId:    c.OrgId,
		AlertIds: []int64{alertId},
		Paused:   dto.Paused,
	}

	if err := bus.Dispatch(&cmd); err != nil {
		return ApiError(500, "", err)
	}

	var response models.AlertStateType = models.AlertStatePending
	pausedState := "un paused"
	if cmd.Paused {
		response = models.AlertStatePaused
		pausedState = "paused"
	}

	result := map[string]interface{}{
		"alertId": alertId,
		"state":   response,
		"message": "alert " + pausedState,
	}

	return Json(200, result)
}

//POST /api/alerts/pause
func PauseAlerts(c *middleware.Context, dto dtos.PauseAlertsCommand) Response {
	alertIdsToUpdate, err := getAlertIdsToUpdate(dto)
	if err != nil {
		return ApiError(500, "Failed to pause alerts", err)
	}

	updateCmd := models.PauseAlertCommand{
		OrgId:    c.OrgId,
		AlertIds: alertIdsToUpdate,
		Paused:   dto.Paused,
	}

	if err := bus.Dispatch(&updateCmd); err != nil {
		return ApiError(500, "Failed to pause alerts", err)
	}

	var response models.AlertStateType = models.AlertStatePending
	pausedState := "un paused"
	if updateCmd.Paused {
		response = models.AlertStatePaused
		pausedState = "paused"
	}

	result := map[string]interface{}{
		"state":          response,
		"message":        "alert " + pausedState,
		"alertsAffected": updateCmd.ResultCount,
	}

	return Json(200, result)
}

func getAlertIdsToUpdate(pauseAlertCmd dtos.PauseAlertsCommand) ([]int64, error) {
	cmd := &models.GetAllAlertsQuery{}
	if err := bus.Dispatch(cmd); err != nil {
		return nil, err
	}

	var alertIdsToUpdate []int64
	updateAllAlerts := len(pauseAlertCmd.DataSourceIds) == 0
	for _, alert := range cmd.Result {
		if updateAllAlerts {
			alertIdsToUpdate = append(alertIdsToUpdate, alert.Id)
			continue
		}

		alert, err := alerting.NewRuleFromDBAlert(alert)
		if err != nil {
			return nil, err
		}

		for _, condition := range alert.Conditions {
			id, exist := condition.GetDatsourceId()
			if exist && existInSlice(pauseAlertCmd.DataSourceIds, *id) {
				alertIdsToUpdate = append(alertIdsToUpdate, alert.Id)
			}
		}
	}

	return alertIdsToUpdate, nil
}

func existInSlice(slice []int64, value int64) bool {
	for _, v := range slice {
		if v == value {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2018 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build privileged_tests

package bpf

import (
	"fmt"
	"os"
	"testing"

	. "gopkg.in/check.v1"

	"github.com/cilium/cilium/pkg/checker"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }

type BPFTestSuite struct{}

var _ = Suite(&BPFTestSuite{})

var (
	maxEntries = 2

	testMap = NewMap("cilium_test",
		MapTypeHash,
		4,
		4,
		maxEntries,
		BPF_F_NO_PREALLOC,
		0,
		nil)
)

func runTests(m *testing.M) (int, error) {
	CheckOrMountFS("")

	_, err := testMap.OpenOrCreate()
	if err != nil {
		return 1, fmt.Errorf("Failed to create map")
	}
	defer func() {
		path, _ := testMap.Path()
		os.Remove(path)
	}()
	defer testMap.Close()

	return m.Run(), nil
}

func TestMain(m *testing.M) {
	exitCode, err := runTests(m)
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(exitCode)
}

func (s *BPFTestSuite) TestGetMapInfo(c *C) {
	mi, err := GetMapInfo(os.Getpid(), testMap.fd)
	c.Assert(err, IsNil)
	c.Assert(&testMap.MapInfo, checker.DeepEquals, mi)
}
<commit_msg>pkg/bpf: Add unit test for Map.Open<commit_after>// Copyright 2018 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build privileged_tests

package bpf

import (
	"fmt"
	"os"
	"testing"

	. "gopkg.in/check.v1"

	"github.com/cilium/cilium/pkg/checker"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }

type BPFTestSuite struct{}

var _ = Suite(&BPFTestSuite{})

var (
	maxEntries = 2

	testMap = NewMap("cilium_test",
		MapTypeHash,
		4,
		4,
		maxEntries,
		BPF_F_NO_PREALLOC,
		0,
		nil)
)

func runTests(m *testing.M) (int, error) {
	CheckOrMountFS("")

	_, err := testMap.OpenOrCreate()
	if err != nil {
		return 1, fmt.Errorf("Failed to create map")
	}
	defer func() {
		path, _ := testMap.Path()
		os.Remove(path)
	}()
	defer testMap.Close()

	return m.Run(), nil
}

func TestMain(m *testing.M) {
	exitCode, err := runTests(m)
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(exitCode)
}

func (s *BPFTestSuite) TestGetMapInfo(c *C) {
	mi, err := GetMapInfo(os.Getpid(), testMap.fd)
	c.Assert(err, IsNil)
	c.Assert(&testMap.MapInfo, checker.DeepEquals, mi)
}

func (s *BPFTestSuite) TestOpen(c *C) {
	// Ensure that os.IsNotExist() can be used with Map.Open()
	noSuchMap := NewMap("cilium_test_no_exist",
		MapTypeHash, 4, 4, maxEntries, 0, 0, nil)
	err := noSuchMap.Open()
	c.Assert(os.IsNotExist(err), Equals, true)
	c.Assert(err, ErrorMatches, ".*cilium_test_no_exist.*")

	// existingMap is the same as testMap. Opening should succeed.
	existingMap := NewMap("cilium_test",
		MapTypeHash,
		4,
		4,
		maxEntries,
		BPF_F_NO_PREALLOC,
		0,
		nil)
	err = existingMap.Open()
	c.Check(err, IsNil)      // Avoid assert to ensure Close() is called below.
	err = existingMap.Open() // Reopen should be no-op.
	c.Check(err, IsNil)
	err = existingMap.Close()
	c.Assert(err, IsNil)
}
<|endoftext|>


<commit_before>package chClient

import (
	"time"
)

func waitNextAttempt(attempt uint) {
	duration := 500 * time.Duration(attempt+1) * time.Millisecond
	if duration < time.Minute {
		time.Sleep(duration)
	} else {
		time.Sleep(time.Minute)
	}
}

func retry(maxTimes uint, fn func() error) error {
	var err error
	for i := uint(0); i == 0 || (i < maxTimes && err != nil); i++ {
		err = fn()
		if err == nil {
			break
		}
		waitNextAttempt(i)
	}
	return err
}
<commit_msg>add retry continue condition<commit_after>package chClient

import (
	"time"
)

func waitNextAttempt(attempt uint) {
	duration := 500 * time.Duration(attempt+1) * time.Millisecond
	if duration < time.Minute {
		time.Sleep(duration)
	} else {
		time.Sleep(time.Minute)
	}
}

func retry(maxTimes uint, fn func() (bool, error)) error {
	var err error
	var ok bool
	for i := uint(0); i == 0 || (i < maxTimes && err != nil); i++ {
		ok, err = fn()
		if err == nil || !ok {
			break
		}
		waitNextAttempt(i)
	}
	return err
}
<|endoftext|>


<commit_before>package cmd

import (
	"errors"

	cli "github.com/spf13/cobra"
	"github.com/tmrts/boilr/pkg/util/exit"
	"github.com/tmrts/boilr/pkg/util/validate"
)

var (
	// ErrTemplateInvalid indicates that the template is invalid.
	ErrTemplateInvalid = errors.New("validate: given template is invalid")
)

// Validate contains the cli-command for validating templates.
var Validate = &cli.Command{
	Use:   "validate",
	Short: "Validate a template",
	Run: func(_ *cli.Command, args []string) {
		MustValidateArgs(args, []validate.Argument{
			{"template-path", validate.UnixPath},
		})

		templatePath := args[0]

		MustValidateTemplate(templatePath)

		exit.OK("Template is valid")
	},
}
<commit_msg>pkg/cmd/validate: include arguments in the cmd usage<commit_after>package cmd

import (
	"errors"

	cli "github.com/spf13/cobra"
	"github.com/tmrts/boilr/pkg/util/exit"
	"github.com/tmrts/boilr/pkg/util/validate"
)

var (
	// ErrTemplateInvalid indicates that the template is invalid.
	ErrTemplateInvalid = errors.New("validate: given template is invalid")
)

// Validate contains the cli-command for validating templates.
var Validate = &cli.Command{
	Use:   "validate <template-path>",
	Short: "Validate a local project template",
	Run: func(_ *cli.Command, args []string) {
		MustValidateArgs(args, []validate.Argument{
			{"template-path", validate.UnixPath},
		})

		templatePath := args[0]

		MustValidateTemplate(templatePath)

		exit.OK("Template is valid")
	},
}
<|endoftext|>