// Test closing the client end of the connection.
func TestConnectionCloseInterrupt2(t *testing.T) {
	want := amqp.Error{Name: "x", Description: "bad"}
	pairs := newPairs(t, 1, true)
	results := make(chan result) // Collect expected errors

	// Connection.Close() interrupts Send, Receive, Disposition.
	snd, rcv := pairs.senderReceiver()
	go doSend(snd, results)
	rcv.Receive()

	rcv, snd = pairs.receiverSender()
	go doReceive(rcv, results)

	snd, rcv = pairs.senderReceiver()
	ack := snd.SendWaitable(amqp.NewMessage())
	go doDisposition(ack, results)

	pairs.client.Connection().Close(want)
	for i := 0; i < 3; i++ {
		if r := <-results; want != r.err {
			// TODO aconway 2015-10-06: Not propagating the correct error, seeing nil.
			t.Logf("want %v got %v", want, r.err)
		}
	}
}
예제 #2
0
// Test closing the server end of a connection.
func TestConnectionCloseInterrupt1(t *testing.T) {
	want := amqp.Error{Name: "x", Description: "bad"}
	pairs := newPairs(t, 1, true)
	results := make(chan result) // Collect expected errors

	// Connection.Close() interrupts Send, Receive, Disposition.
	snd, rcv := pairs.senderReceiver()
	go doSend(snd, results)

	rcv.Receive()
	rcv, snd = pairs.receiverSender()
	go doReceive(rcv, results)

	snd, rcv = pairs.senderReceiver()
	ack := snd.SendWaitable(amqp.NewMessage())
	rcv.Receive()
	go doDisposition(ack, results)

	pairs.server.Close(want)
	for i := 0; i < 3; i++ {
		if r := <-results; want != r.err {
			t.Errorf("want %v got %v", want, r)
		}
	}
}
예제 #3
0
// Senders get credit immediately if receivers have prefetch set
func TestSendReceivePrefetch(t *testing.T) {
	pairs := newPairs(t, 1, true)
	s, r := pairs.senderReceiver()
	s.SendAsyncTimeout(amqp.NewMessage(), nil, nil, time.Second) // Should not block for credit.
	if _, err := r.Receive(); err != nil {
		t.Error(err)
	}
}
예제 #4
0
// Message decodes the message containined in a delivery.
//
// Must be called in the correct link context with this delivery as the current message,
// handling an MMessage event is always a safe context to call this function.
//
// Will return an error if message is incomplete or not current.
func (delivery Delivery) Message() (m amqp.Message, err error) {
	if !delivery.Readable() {
		return nil, fmt.Errorf("delivery is not readable")
	}
	if delivery.Partial() {
		return nil, fmt.Errorf("delivery has partial message")
	}
	data := make([]byte, delivery.Pending())
	result := delivery.Link().Recv(data)
	if result != len(data) {
		return nil, fmt.Errorf("cannot receive message: %s", PnErrorCode(result))
	}
	m = amqp.NewMessage()
	err = m.Decode(data)
	return
}
예제 #5
0
// Senders do not get credit till Receive() if receivers don't have prefetch
func TestSendReceiveNoPrefetch(t *testing.T) {
	pairs := newPairs(t, 1, false)
	s, r := pairs.senderReceiver()
	done := make(chan struct{}, 1)
	go func() {
		s.SendAsyncTimeout(amqp.NewMessage(), nil, nil, time.Second) // Should block for credit.
		close(done)
	}()
	select {
	case <-done:
		t.Errorf("send should be blocked on credit")
	default:
		if _, err := r.Receive(); err != nil {
			t.Error(err)
		} else {
			<-done
		} // Should be unblocked now
	}
}
예제 #6
0
// Test closing the client end of the connection.
func TestConnectionCloseInterrupt2(t *testing.T) {
	want := amqp.Errorf("x", "bad")
	pairs := newPairs(t)
	results := make(chan result) // Collect expected errors

	// Connection.Close() interrupts Send, Receive, Disposition.
	snd, rcv := pairs.senderReceiver()
	go doReceive(rcv, results)
	sm, err := snd.Send(amqp.NewMessage())
	fatalIf(t, err)
	go doDisposition(sm, results)
	snd, rcv = pairs.senderReceiver()
	go doSend(snd, results)
	rcv, snd = pairs.receiverSender()
	go doReceive(rcv, results)
	pairs.client.Close(want)
	for i := 0; i < 3; i++ {
		if r := <-results; want != r.err {
			// TODO aconway 2015-10-06: Not propagating the correct error, seeing nil.
			t.Logf("want %v got %v", want, r.err)
		}
	}
}
예제 #7
0
파일: send.go 프로젝트: ChugR/qpid-proton
func main() {
	flag.Usage = usage
	flag.Parse()

	urls := flag.Args() // Non-flag arguments are URLs to receive from
	if len(urls) == 0 {
		log.Println("No URL provided")
		flag.Usage()
		os.Exit(1)
	}

	sentChan := make(chan electron.Outcome) // Channel to receive acknowledgements.

	var wait sync.WaitGroup
	wait.Add(len(urls)) // Wait for one goroutine per URL.

	_, prog := path.Split(os.Args[0])
	container := electron.NewContainer(fmt.Sprintf("%v:%v", prog, os.Getpid()))
	connections := make(chan electron.Connection, len(urls)) // Connctions to close on exit

	// Start a goroutine for each URL to send messages.
	for _, urlStr := range urls {
		util.Debugf("Connecting to %v\n", urlStr)
		go func(urlStr string) {

			defer wait.Done()                 // Notify main() that this goroutine is done.
			url, err := amqp.ParseURL(urlStr) // Like net/url.Parse() but with AMQP defaults.
			util.ExitIf(err)

			// Open a new connection
			conn, err := net.Dial("tcp", url.Host) // Note net.URL.Host is actually "host:port"
			util.ExitIf(err)
			c, err := container.Connection(conn)
			util.ExitIf(err)
			connections <- c // Save connection so we can Close() when main() ends

			// Create a Sender using the path of the URL as the AMQP address
			s, err := c.Sender(electron.Target(url.Path))
			util.ExitIf(err)

			// Loop sending messages.
			for i := int64(0); i < *count; i++ {
				m := amqp.NewMessage()
				body := fmt.Sprintf("%v-%v", url.Path, i)
				m.Marshal(body)
				s.SendAsync(m, sentChan, body) // Outcome will be sent to sentChan
			}
		}(urlStr)
	}

	// Wait for all the acknowledgements
	expect := int(*count) * len(urls)
	util.Debugf("Started senders, expect %v acknowledgements\n", expect)
	for i := 0; i < expect; i++ {
		out := <-sentChan // Outcome of async sends.
		if out.Error != nil {
			util.Debugf("acknowledgement[%v] %v error: %v\n", i, out.Value, out.Error)
		} else {
			util.Debugf("acknowledgement[%v]  %v (%v)\n", i, out.Value, out.Status)
		}
	}
	fmt.Printf("Received all %v acknowledgements\n", expect)

	wait.Wait() // Wait for all goroutines to finish.
	close(connections)
	for c := range connections { // Close all connections
		if c != nil {
			c.Close(nil)
		}
	}
}
예제 #8
0
func doSend(snd Sender, results chan result) {
	_, err := snd.Send(amqp.NewMessage())
	results <- result{"send", err}
}
예제 #9
0
// Test timeout versions of waiting functions.
func TestTimeouts(t *testing.T) {
	var err error
	rchan := make(chan Receiver, 1)
	client, server := newClientServer(t, func(i Incoming) {
		switch i := i.(type) {
		case *IncomingReceiver:
			rchan <- i.AcceptReceiver(1, false) // Issue credit only on receive
		default:
			i.Accept()
		}
	})
	defer func() { closeClientServer(client, server) }()

	// Open client sender
	snd, err := client.Sender(Target("test"))
	if err != nil {
		t.Fatal(err)
	}
	rcv := <-rchan

	// Test send with timeout
	short := time.Millisecond
	long := time.Second
	m := amqp.NewMessage()
	if _, err = snd.SendTimeout(m, 0); err != Timeout { // No credit, expect timeout.
		t.Error("want Timeout got", err)
	}
	if _, err = snd.SendTimeout(m, short); err != Timeout { // No credit, expect timeout.
		t.Error("want Timeout got", err)
	}
	// Test receive with timeout
	if _, err = rcv.ReceiveTimeout(0); err != Timeout { // No credit, expect timeout.
		t.Error("want Timeout got", err)
	}
	// Test receive with timeout
	if _, err = rcv.ReceiveTimeout(short); err != Timeout { // No credit, expect timeout.
		t.Error("want Timeout got", err)
	}
	// There is now a credit on the link due to receive
	sm, err := snd.SendTimeout(m, long)
	if err != nil {
		t.Fatal(err)
	}
	// Disposition should timeout
	if _, err = sm.DispositionTimeout(long); err != Timeout {
		t.Error("want Timeout got", err)
	}
	if _, err = sm.DispositionTimeout(short); err != Timeout {
		t.Error("want Timeout got", err)
	}
	// Receive and accept
	rm, err := rcv.ReceiveTimeout(long)
	if err != nil {
		t.Fatal(err)
	}
	rm.Accept()
	// Sender get ack
	d, err := sm.DispositionTimeout(long)
	if err != nil || d != Accepted {
		t.Errorf("want (rejected, nil) got (%v, %v)", d, err)
	}
}
예제 #10
0
func doSend(snd Sender, results chan result) {
	err := snd.SendSync(amqp.NewMessage()).Error
	results <- result{"send", err}
}
예제 #11
0
// Test timeout versions of waiting functions.
func TestTimeouts(t *testing.T) {
	var err error
	rchan := make(chan Receiver, 1)
	client, server := newClientServer(t)
	go func() {
		for i := range server.Incoming() {
			switch i := i.(type) {
			case *IncomingReceiver:
				i.SetCapacity(1)
				i.SetPrefetch(false)
				rchan <- i.Accept().(Receiver) // Issue credit only on receive
			default:
				i.Accept()
			}
		}
	}()
	defer func() { closeClientServer(client, server) }()

	// Open client sender
	snd, err := client.Sender(Target("test"))
	if err != nil {
		t.Fatal(err)
	}
	rcv := <-rchan

	// Test send with timeout
	short := time.Millisecond
	long := time.Second
	m := amqp.NewMessage()
	if err := snd.SendSyncTimeout(m, 0).Error; err != Timeout { // No credit, expect timeout.
		t.Error("want Timeout got", err)
	}
	if err := snd.SendSyncTimeout(m, short).Error; err != Timeout { // No credit, expect timeout.
		t.Error("want Timeout got", err)
	}
	// Test receive with timeout
	if _, err = rcv.ReceiveTimeout(0); err != Timeout { // No credit, expect timeout.
		t.Error("want Timeout got", err)
	}
	// Test receive with timeout
	if _, err = rcv.ReceiveTimeout(short); err != Timeout { // No credit, expect timeout.
		t.Error("want Timeout got", err)
	}
	// There is now a credit on the link due to receive
	ack := make(chan Outcome)
	snd.SendAsyncTimeout(m, ack, nil, short)
	// Disposition should timeout
	select {
	case <-ack:
		t.Errorf("want Timeout got %#v", ack)
	case <-time.After(short):
	}

	// Receive and accept
	rm, err := rcv.ReceiveTimeout(long)
	if err != nil {
		t.Fatal(err)
	}
	rm.Accept()
	// Sender get ack
	if a := <-ack; a.Status != Accepted || a.Error != nil {
		t.Errorf("want (accepted, nil) got %#v", a)
	}
}