// Copyright 2019-2025 The NATS 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.

//go:build !skip_js_tests

package server

import (
	"bytes"
	"context"
	crand "crypto/rand"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"math"
	"math/big"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"runtime/debug"
	"slices"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/nats-io/jwt/v2"
	"github.com/nats-io/nats-server/v2/server/sysmem"
	"github.com/nats-io/nats.go"
	"github.com/nats-io/nats.go/jetstream"
	"github.com/nats-io/nkeys"
	"github.com/nats-io/nuid"
)

func TestJetStreamBasicNilConfig(t *testing.T) {
	s := RunRandClientPortServer(t)
	defer s.Shutdown()

	if err := s.EnableJetStream(nil); err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if !s.JetStreamEnabled() {
		t.Fatalf("Expected JetStream to be enabled")
	}
	if s.SystemAccount() == nil {
		t.Fatalf("Expected system account to be created automatically")
	}
	// Grab our config since it was dynamically generated.
	config := s.JetStreamConfig()
	if config == nil {
		t.Fatalf("Expected non-nil config")
	}
	// Check dynamic max memory.
	hwMem := sysmem.Memory()
	if hwMem != 0 {
		// Check if memory being limited via GOMEMLIMIT if being set.
		if gml := debug.SetMemoryLimit(-1); gml != math.MaxInt64 {
			hwMem = gml
		}
		// Make sure its about 75%
		est := hwMem / 4 * 3
		if config.MaxMemory != est {
			t.Fatalf("Expected memory to be 80 percent of system memory, got %v vs %v", config.MaxMemory, est)
		}
	}
	// Make sure it was created.
	stat, err := os.Stat(config.StoreDir)
	if err != nil {
		t.Fatalf("Expected the store directory to be present, %v", err)
	}
	if stat == nil || !stat.IsDir() {
		t.Fatalf("Expected a directory")
	}
}

func RunBasicJetStreamServer(t testing.TB) *Server {
	opts := DefaultTestOptions
	opts.Port = -1
	opts.JetStream = true
	opts.StoreDir = t.TempDir()
	return RunServer(&opts)
}

func RunJetStreamServerOnPort(port int, sd string) *Server {
	opts := DefaultTestOptions
	opts.Port = port
	opts.JetStream = true
	opts.StoreDir = filepath.Dir(sd)
	return RunServer(&opts)
}

func clientConnectToServer(t *testing.T, s *Server) *nats.Conn {
	t.Helper()
	nc, err := nats.Connect(s.ClientURL(),
		nats.Name("JS-TEST"),
		nats.ReconnectWait(5*time.Millisecond),
		nats.MaxReconnects(-1))
	if err != nil {
		t.Fatalf("Failed to create client: %v", err)
	}
	return nc
}

func clientConnectWithOldRequest(t *testing.T, s *Server) *nats.Conn {
	nc, err := nats.Connect(s.ClientURL(), nats.UseOldRequestStyle())
	if err != nil {
		t.Fatalf("Failed to create client: %v", err)
	}
	return nc
}

func TestJetStreamEnableAndDisableAccount(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Global in simple setup should be enabled already.
	if !s.GlobalAccount().JetStreamEnabled() {
		t.Fatalf("Expected to have jetstream enabled on global account")
	}
	if na := s.JetStreamNumAccounts(); na != 1 {
		t.Fatalf("Expected 1 account, got %d", na)
	}

	if err := s.GlobalAccount().DisableJetStream(); err != nil {
		t.Fatalf("Did not expect error on disabling account: %v", err)
	}
	if na := s.JetStreamNumAccounts(); na != 0 {
		t.Fatalf("Expected no accounts, got %d", na)
	}
	// Make sure we unreserved resources.
	if rm, rd, err := s.JetStreamReservedResources(); err != nil {
		t.Fatalf("Unexpected error requesting jetstream reserved resources: %v", err)
	} else if rm != 0 || rd != 0 {
		t.Fatalf("Expected reserved memory and store to be 0, got %v and %v", friendlyBytes(rm), friendlyBytes(rd))
	}

	acc, _ := s.LookupOrRegisterAccount("$FOO")
	if err := acc.EnableJetStream(nil); err != nil {
		t.Fatalf("Did not expect error on enabling account: %v", err)
	}
	if na := s.JetStreamNumAccounts(); na != 1 {
		t.Fatalf("Expected 1 account, got %d", na)
	}
	if err := acc.DisableJetStream(); err != nil {
		t.Fatalf("Did not expect error on disabling account: %v", err)
	}
	if na := s.JetStreamNumAccounts(); na != 0 {
		t.Fatalf("Expected no accounts, got %d", na)
	}
	// We should get error if disabling something not enabled.
	acc, _ = s.LookupOrRegisterAccount("$BAR")
	if err := acc.DisableJetStream(); err == nil {
		t.Fatalf("Expected error on disabling account that was not enabled")
	}
	// Should get an error for trying to enable a non-registered account.
	acc = NewAccount("$BAZ")
	if err := acc.EnableJetStream(nil); err == nil {
		t.Fatalf("Expected error on enabling account that was not registered")
	}
}

func TestJetStreamAddStream(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{name: "MemoryStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   MemoryStorage,
				Replicas:  1,
			}},
		{name: "FileStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   FileStorage,
				Replicas:  1,
			}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			js.Publish("foo", []byte("Hello World!"))
			state := mset.state()
			if state.Msgs != 1 {
				t.Fatalf("Expected 1 message, got %d", state.Msgs)
			}
			if state.Bytes == 0 {
				t.Fatalf("Expected non-zero bytes")
			}

			js.Publish("foo", []byte("Hello World Again!"))
			state = mset.state()
			if state.Msgs != 2 {
				t.Fatalf("Expected 2 messages, got %d", state.Msgs)
			}

			if err := mset.delete(); err != nil {
				t.Fatalf("Got an error deleting the stream: %v", err)
			}
		})
	}
}

func TestJetStreamAddStreamDiscardNew(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{name: "MemoryStore",
			mconfig: &StreamConfig{
				Name:     "foo",
				MaxMsgs:  10,
				MaxBytes: 4096,
				Discard:  DiscardNew,
				Storage:  MemoryStorage,
				Replicas: 1,
			}},
		{name: "FileStore",
			mconfig: &StreamConfig{
				Name:     "foo",
				MaxMsgs:  10,
				MaxBytes: 4096,
				Discard:  DiscardNew,
				Storage:  FileStorage,
				Replicas: 1,
			}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			subj := "foo"
			toSend := 10
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, subj, fmt.Sprintf("MSG: %d", i+1))
			}
			// We expect this one to fail due to discard policy.
			resp, _ := nc.Request(subj, []byte("discard me"), 100*time.Millisecond)
			if resp == nil {
				t.Fatalf("No response, possible timeout?")
			}
			if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error.Description != "maximum messages exceeded" || pa.Stream != "foo" {
				t.Fatalf("Expected to get an error about maximum messages, got %q", resp.Data)
			}

			// Now do bytes.
			mset.purge(nil)

			big := make([]byte, 8192)
			resp, _ = nc.Request(subj, big, 100*time.Millisecond)
			if resp == nil {
				t.Fatalf("No response, possible timeout?")
			}
			if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error.Description != "maximum bytes exceeded" || pa.Stream != "foo" {
				t.Fatalf("Expected to get an error about maximum bytes, got %q", resp.Data)
			}
		})
	}
}

func TestJetStreamAutoTuneFSConfig(t *testing.T) {
	s := RunRandClientPortServer(t)
	defer s.Shutdown()

	jsconfig := &JetStreamConfig{MaxMemory: -1, MaxStore: 128 * 1024 * 1024, StoreDir: t.TempDir()}
	if err := s.EnableJetStream(jsconfig); err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}

	maxMsgSize := int32(512)
	streamConfig := func(name string, maxMsgs, maxBytes int64) *StreamConfig {
		t.Helper()
		cfg := &StreamConfig{Name: name, MaxMsgSize: maxMsgSize, Storage: FileStorage}
		if maxMsgs > 0 {
			cfg.MaxMsgs = maxMsgs
		}
		if maxBytes > 0 {
			cfg.MaxBytes = maxBytes
		}
		return cfg
	}

	acc := s.GlobalAccount()

	testBlkSize := func(name string, maxMsgs, maxBytes int64, expectedBlkSize uint64) {
		t.Helper()
		mset, err := acc.addStream(streamConfig(name, maxMsgs, maxBytes))
		if err != nil {
			t.Fatalf("Unexpected error adding stream: %v", err)
		}
		defer mset.delete()
		fsCfg, err := mset.fileStoreConfig()
		if err != nil {
			t.Fatalf("Unexpected error retrieving file store: %v", err)
		}
		if fsCfg.BlockSize != expectedBlkSize {
			t.Fatalf("Expected auto tuned block size to be %d, got %d", expectedBlkSize, fsCfg.BlockSize)
		}
	}

	// Create a dummy stream, to ensure removing stream/account directories don't race.
	_, err := acc.addStream(streamConfig("dummy", 1, 0))
	require_NoError(t, err)

	testBlkSize("foo", 1, 0, FileStoreMinBlkSize)
	testBlkSize("foo", 1, 512, FileStoreMinBlkSize)
	testBlkSize("foo", 1, 1024*1024, defaultMediumBlockSize)
	testBlkSize("foo", 1, 8*1024*1024, defaultMediumBlockSize)
	testBlkSize("foo_bar_baz", -1, 32*1024*1024, FileStoreMaxBlkSize)
}

func TestJetStreamPubAck(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	sname := "PUBACK"
	acc := s.GlobalAccount()
	mconfig := &StreamConfig{Name: sname, Subjects: []string{"foo"}, Storage: MemoryStorage}
	mset, err := acc.addStream(mconfig)
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	checkRespDetails := func(resp *nats.Msg, err error, seq uint64) {
		if err != nil {
			t.Fatalf("Unexpected error from send stream msg: %v", err)
		}
		if resp == nil {
			t.Fatalf("No response from send stream msg")
		}
		pa := getPubAckResponse(resp.Data)
		if pa == nil || pa.Error != nil {
			t.Fatalf("Expected a valid JetStreamPubAck, got %q", resp.Data)
		}
		if pa.Stream != sname {
			t.Fatalf("Expected %q for stream name, got %q", sname, pa.Stream)
		}
		if pa.Sequence != seq {
			t.Fatalf("Expected %d for sequence, got %d", seq, pa.Sequence)
		}
	}

	// Send messages and make sure pubAck details are correct.
	for i := uint64(1); i <= 1000; i++ {
		resp, err := nc.Request("foo", []byte("HELLO"), 100*time.Millisecond)
		checkRespDetails(resp, err, i)
	}
}

func TestJetStreamNextReqFromMsg(t *testing.T) {
	bef := time.Now()
	expires, _, _, _, _, _, _, err := nextReqFromMsg([]byte(`{"expires":5000000000}`)) // nanoseconds
	require_NoError(t, err)
	now := time.Now()
	if expires.Before(bef.Add(5*time.Second)) || expires.After(now.Add(5*time.Second)) {
		t.Fatal("Expires out of expected range")
	}
}

func TestJetStreamNoPanicOnRaceBetweenShutdownAndConsumerDelete(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_STREAM", Storage: MemoryStorage}},
		{"FileStore", &StreamConfig{Name: "MY_STREAM", Storage: FileStorage}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			var cons []*consumer
			for i := 0; i < 100; i++ {
				o, err := mset.addConsumer(&ConsumerConfig{
					Durable:   fmt.Sprintf("d%d", i),
					AckPolicy: AckExplicit,
				})
				require_NoError(t, err)
				defer o.delete()
				cons = append(cons, o)
			}

			wg := sync.WaitGroup{}
			wg.Add(1)
			go func() {
				defer wg.Done()
				for _, c := range cons {
					c.delete()
				}
			}()
			time.Sleep(10 * time.Millisecond)
			s.Shutdown()
		})
	}
}

func TestJetStreamAddStreamMaxMsgSize(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{name: "MemoryStore",
			mconfig: &StreamConfig{
				Name:       "foo",
				Retention:  LimitsPolicy,
				MaxAge:     time.Hour,
				Storage:    MemoryStorage,
				MaxMsgSize: 22,
				Replicas:   1,
			}},
		{name: "FileStore",
			mconfig: &StreamConfig{
				Name:       "foo",
				Retention:  LimitsPolicy,
				MaxAge:     time.Hour,
				Storage:    FileStorage,
				MaxMsgSize: 22,
				Replicas:   1,
			}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			if _, err := nc.Request("foo", []byte("Hello World!"), time.Second); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}

			tooBig := []byte("1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ")
			resp, err := nc.Request("foo", tooBig, time.Second)
			require_NoError(t, err)
			if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error.Description != "message size exceeds maximum allowed" {
				t.Fatalf("Expected to get an error for maximum message size, got %q", pa.Error)
			}
		})
	}
}

func TestJetStreamAddStreamCanonicalNames(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()

	expectErr := func(_ *stream, err error) {
		t.Helper()
		if !IsNatsErr(err, JSStreamInvalidConfigF) {
			t.Fatalf("Expected error but got none")
		}
	}

	expectErr(acc.addStream(&StreamConfig{Name: "foo.bar"}))
	expectErr(acc.addStream(&StreamConfig{Name: "foo.bar."}))
	expectErr(acc.addStream(&StreamConfig{Name: "foo.*"}))
	expectErr(acc.addStream(&StreamConfig{Name: "foo.>"}))
	expectErr(acc.addStream(&StreamConfig{Name: "*"}))
	expectErr(acc.addStream(&StreamConfig{Name: ">"}))
	expectErr(acc.addStream(&StreamConfig{Name: "*>"}))
}

func TestJetStreamAddStreamBadSubjects(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc := clientConnectToServer(t, s)
	defer nc.Close()

	expectAPIErr := func(cfg StreamConfig) {
		t.Helper()
		req, err := json.Marshal(cfg)
		require_NoError(t, err)
		resp, _ := nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
		var scResp JSApiStreamCreateResponse
		if err := json.Unmarshal(resp.Data, &scResp); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		require_Error(t, scResp.ToError(), NewJSStreamInvalidConfigError(fmt.Errorf("invalid subject")))
	}

	expectAPIErr(StreamConfig{Name: "MyStream", Storage: MemoryStorage, Subjects: []string{"foo.bar."}})
	expectAPIErr(StreamConfig{Name: "MyStream", Storage: MemoryStorage, Subjects: []string{".."}})
	expectAPIErr(StreamConfig{Name: "MyStream", Storage: MemoryStorage, Subjects: []string{".*"}})
	expectAPIErr(StreamConfig{Name: "MyStream", Storage: MemoryStorage, Subjects: []string{".>"}})
	expectAPIErr(StreamConfig{Name: "MyStream", Storage: MemoryStorage, Subjects: []string{" x"}})
	expectAPIErr(StreamConfig{Name: "MyStream", Storage: MemoryStorage, Subjects: []string{"y "}})
}

func TestJetStreamMaxConsumers(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	cfg := &nats.StreamConfig{
		Name:         "MAXC",
		Storage:      nats.MemoryStorage,
		Subjects:     []string{"in.maxc.>"},
		MaxConsumers: 2,
	}
	if _, err := js.AddStream(cfg); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	si, err := js.StreamInfo("MAXC")
	require_NoError(t, err)
	if si.Config.MaxConsumers != 2 {
		t.Fatalf("Expected max of 2, got %d", si.Config.MaxConsumers)
	}
	// Make sure we get the right error.
	// This should succeed.
	if _, err := js.PullSubscribe("in.maxc.foo", "maxc_foo"); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	// Create for the same consumer must be idempotent, and not trigger limit.
	if _, err := js.PullSubscribe("in.maxc.foo", "maxc_foo"); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// Create (with explicit create API) for the same consumer must be idempotent, and not trigger limit.
	obsReq := CreateConsumerRequest{
		Stream: "MAXC",
		Config: ConsumerConfig{Durable: "maxc_baz"},
		Action: ActionCreate,
	}
	req, err := json.Marshal(obsReq)
	require_NoError(t, err)

	msg, err := nc.Request(fmt.Sprintf(JSApiDurableCreateT, "MAXC", "maxc_baz"), req, time.Second)
	require_NoError(t, err)
	var resp JSApiConsumerInfoResponse
	require_NoError(t, json.Unmarshal(msg.Data, &resp))
	if resp.Error != nil {
		t.Fatalf("Unexpected error: %v", resp.Error)
	}

	msg, err = nc.Request(fmt.Sprintf(JSApiDurableCreateT, "MAXC", "maxc_baz"), req, time.Second)
	require_NoError(t, err)
	var resp2 JSApiConsumerInfoResponse
	require_NoError(t, json.Unmarshal(msg.Data, &resp2))
	if resp2.Error != nil {
		t.Fatalf("Unexpected error: %v", resp2.Error)
	}

	// Exceeds limit.
	if _, err := js.SubscribeSync("in.maxc.bar"); err == nil {
		t.Fatalf("Expected error but got none")
	}
}

func TestJetStreamAddStreamOverlappingSubjects(t *testing.T) {
	mconfig := &StreamConfig{
		Name:     "ok",
		Storage:  MemoryStorage,
		Subjects: []string{"foo", "bar", "baz.*", "foo.bar.baz.>"},
	}

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()
	mset, err := acc.addStream(mconfig)
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	expectErr := func(_ *stream, err error) {
		t.Helper()
		if err == nil || !strings.Contains(err.Error(), "subjects overlap") {
			t.Fatalf("Expected error but got none")
		}
	}

	// Test that any overlapping subjects will fail.
	expectErr(acc.addStream(&StreamConfig{Name: "foo"}))
	expectErr(acc.addStream(&StreamConfig{Name: "a", Subjects: []string{"baz", "bar"}}))
	expectErr(acc.addStream(&StreamConfig{Name: "b", Subjects: []string{">"}, NoAck: true}))
	expectErr(acc.addStream(&StreamConfig{Name: "c", Subjects: []string{"baz.33"}}))

	// Using NoAck on the following because technically they overlap with the $JS.> namespace...
	expectErr(acc.addStream(&StreamConfig{Name: "d", Subjects: []string{"*.33"}, NoAck: true}))
	expectErr(acc.addStream(&StreamConfig{Name: "e", Subjects: []string{"*.>"}, NoAck: true}))
	expectErr(acc.addStream(&StreamConfig{Name: "f", Subjects: []string{"foo.bar", "*.bar.>"}, NoAck: true}))
}

func TestJetStreamAddStreamOverlapWithJSAPISubjects(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()

	expectNoErr := func(_ *stream, err error) {
		t.Helper()
		switch {
		case err == nil:
		default:
			t.Errorf("Unexpected error: %v", err)
		}
	}

	expectErr := func(_ *stream, err error) {
		t.Helper()
		switch {
		case err == nil:
			t.Errorf("Expected error but got none")
		case !strings.Contains(err.Error(), "subjects that overlap with jetstream api"):
		case !strings.Contains(err.Error(), "subjects that overlap with system api"):
		case !strings.Contains(err.Error(), "capturing all subjects requires no-ack to be true"):
		default:
			t.Errorf("Unexpected error: %v", err)
		}
	}

	// Test that any overlapping subjects with our JSAPI should fail.
	expectErr(acc.addStream(&StreamConfig{Name: "a", Subjects: []string{"$JS.API.foo", "$JS.API.bar"}}))
	expectErr(acc.addStream(&StreamConfig{Name: "b", Subjects: []string{"$JS.API.>"}}))
	expectErr(acc.addStream(&StreamConfig{Name: "c", Subjects: []string{"$JS.API.*"}}))
	expectErr(acc.addStream(&StreamConfig{Name: "d", Subjects: []string{"$JS.>"}}))
	expectErr(acc.addStream(&StreamConfig{Name: "e", Subjects: []string{"$SYS.>"}}))
	expectErr(acc.addStream(&StreamConfig{Name: "f", Subjects: []string{"*.>"}}))
	expectErr(acc.addStream(&StreamConfig{Name: "g", Subjects: []string{">"}}))

	// Events and advisories should be OK.
	expectNoErr(acc.addStream(&StreamConfig{Name: "h", Subjects: []string{"$JS.EVENT.>"}}))
	expectNoErr(acc.addStream(&StreamConfig{Name: "i", Subjects: []string{"$SYS.ACCOUNT.>"}}))

	// So should a full wild-card with NoAck, but need to clean up overlapping streams first.
	for _, name := range []string{"h", "i"} {
		mset, err := acc.lookupStream(name)
		require_NoError(t, err)
		require_NoError(t, mset.delete())
	}
	expectNoErr(acc.addStream(&StreamConfig{Name: "j", Subjects: []string{">"}, NoAck: true}))
}

func TestJetStreamAddStreamSameConfigOK(t *testing.T) {
	mconfig := &StreamConfig{
		Name:     "ok",
		Subjects: []string{"foo", "bar", "baz.*", "foo.bar.baz.>"},
		Storage:  MemoryStorage,
	}

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()
	mset, err := acc.addStream(mconfig)
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	// Adding again with same config should be idempotent.
	if _, err = acc.addStream(mconfig); err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
}

func sendStreamMsg(t *testing.T, nc *nats.Conn, subject, msg string) *PubAck {
	t.Helper()
	resp, err := nc.Request(subject, []byte(msg), 500*time.Millisecond)
	if resp == nil {
		t.Fatalf("No response for %q (error: %v)", msg, err)
	}
	pa := getPubAckResponse(resp.Data)
	if pa == nil || pa.Error != nil {
		t.Fatalf("Expected a valid JetStreamPubAck, got %q", resp.Data)
	}
	return pa.PubAck
}

func TestJetStreamBasicAckPublish(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "foo", Storage: MemoryStorage, Subjects: []string{"foo.*"}}},
		{"FileStore", &StreamConfig{Name: "foo", Storage: FileStorage, Subjects: []string{"foo.*"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			for i := 0; i < 50; i++ {
				sendStreamMsg(t, nc, "foo.bar", "Hello World!")
			}
			state := mset.state()
			if state.Msgs != 50 {
				t.Fatalf("Expected 50 messages, got %d", state.Msgs)
			}
		})
	}
}

func TestJetStreamStateTimestamps(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "foo", Storage: MemoryStorage, Subjects: []string{"foo.*"}}},
		{"FileStore", &StreamConfig{Name: "foo", Storage: FileStorage, Subjects: []string{"foo.*"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			start := time.Now()
			delay := 250 * time.Millisecond
			sendStreamMsg(t, nc, "foo.bar", "Hello World!")
			time.Sleep(delay)
			sendStreamMsg(t, nc, "foo.bar", "Hello World Again!")

			state := mset.state()
			if state.FirstTime.Before(start) {
				t.Fatalf("Unexpected first message timestamp: %v", state.FirstTime)
			}
			if state.LastTime.Before(start.Add(delay)) {
				t.Fatalf("Unexpected last message timestamp: %v", state.LastTime)
			}
		})
	}
}

func TestJetStreamNoAckStream(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "foo", Storage: MemoryStorage, NoAck: true}},
		{"FileStore", &StreamConfig{Name: "foo", Storage: FileStorage, NoAck: true}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			// We can use NoAck to suppress acks even when reply subjects are present.
			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			if _, err := nc.Request("foo", []byte("Hello World!"), 25*time.Millisecond); err != nats.ErrTimeout {
				t.Fatalf("Expected a timeout error and no response with acks suppressed")
			}

			state := mset.state()
			if state.Msgs != 1 {
				t.Fatalf("Expected 1 message, got %d", state.Msgs)
			}
		})
	}
}

func TestJetStreamBasicDeliverSubject(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MSET", Storage: MemoryStorage, Subjects: []string{"foo.*"}}},
		{"FileStore", &StreamConfig{Name: "MSET", Storage: FileStorage, Subjects: []string{"foo.*"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			toSend := 100
			sendSubj := "foo.bar"
			for i := 1; i <= toSend; i++ {
				sendStreamMsg(t, nc, sendSubj, strconv.Itoa(i))
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			// Now create an consumer. Use different connection.
			nc2 := clientConnectToServer(t, s)
			defer nc2.Close()

			sub, _ := nc2.SubscribeSync(nats.NewInbox())
			defer sub.Unsubscribe()
			nc2.Flush()

			o, err := mset.addConsumer(&ConsumerConfig{DeliverSubject: sub.Subject})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			// Check for our messages.
			checkMsgs := func(seqOff int) {
				t.Helper()

				checkFor(t, 250*time.Millisecond, 10*time.Millisecond, func() error {
					if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != toSend {
						return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, toSend)
					}
					return nil
				})

				// Now let's check the messages
				for i := 0; i < toSend; i++ {
					m, _ := sub.NextMsg(time.Second)
					// JetStream will have the subject match the stream subject, not delivery subject.
					if m.Subject != sendSubj {
						t.Fatalf("Expected original subject of %q, but got %q", sendSubj, m.Subject)
					}
					// Now check that reply subject exists and has a sequence as the last token.
					if seq := o.seqFromReply(m.Reply); seq != uint64(i+seqOff) {
						t.Fatalf("Expected sequence of %d , got %d", i+seqOff, seq)
					}
					// Ack the message here.
					m.Respond(nil)
				}
			}

			checkMsgs(1)

			// Now send more and make sure delivery picks back up.
			for i := toSend + 1; i <= toSend*2; i++ {
				sendStreamMsg(t, nc, sendSubj, strconv.Itoa(i))
			}
			state = mset.state()
			if state.Msgs != uint64(toSend*2) {
				t.Fatalf("Expected %d messages, got %d", toSend*2, state.Msgs)
			}

			checkMsgs(101)

			checkSubEmpty := func() {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != 0 {
					t.Fatalf("Expected sub to have no pending")
				}
			}
			checkSubEmpty()
			o.delete()

			// Now check for deliver last, deliver new and deliver by seq.
			o, err = mset.addConsumer(&ConsumerConfig{DeliverSubject: sub.Subject, DeliverPolicy: DeliverLast})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			m, err := sub.NextMsg(time.Second)
			if err != nil {
				t.Fatalf("Did not get expected message, got %v", err)
			}
			// All Consumers start with sequence #1.
			if seq := o.seqFromReply(m.Reply); seq != 1 {
				t.Fatalf("Expected sequence to be 1, but got %d", seq)
			}
			// Check that is the last msg we sent though.
			if mseq, _ := strconv.Atoi(string(m.Data)); mseq != 200 {
				t.Fatalf("Expected message sequence to be 200, but got %d", mseq)
			}

			checkSubEmpty()
			o.delete()

			// Make sure we only got one message.
			if m, err := sub.NextMsg(5 * time.Millisecond); err == nil {
				t.Fatalf("Expected no msg, got %+v", m)
			}

			checkSubEmpty()
			o.delete()

			// Now try by sequence number.
			o, err = mset.addConsumer(&ConsumerConfig{DeliverSubject: sub.Subject, DeliverPolicy: DeliverByStartSequence, OptStartSeq: 101})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			checkMsgs(1)

			// Now do push based queue-subscribers
			sub, _ = nc2.QueueSubscribeSync("_qg_", "dev")
			defer sub.Unsubscribe()
			nc2.Flush()

			o, err = mset.addConsumer(&ConsumerConfig{DeliverSubject: sub.Subject, DeliverGroup: "dev"})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			// Since we sent another batch need check to be looking for 2x.
			toSend *= 2
			checkMsgs(1)
		})
	}
}

func workerModeConfig(name string) *ConsumerConfig {
	return &ConsumerConfig{Durable: name, AckPolicy: AckExplicit}
}

func TestJetStreamBasicWorkQueue(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_MSG_SET", Storage: MemoryStorage, Subjects: []string{"foo", "bar"}}},
		{"FileStore", &StreamConfig{Name: "MY_MSG_SET", Storage: FileStorage, Subjects: []string{"foo", "bar"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			// Create basic work queue mode consumer.
			oname := "WQ"
			o, err := mset.addConsumer(workerModeConfig(oname))
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			if o.nextSeq() != 1 {
				t.Fatalf("Expected to be starting at sequence 1")
			}

			nc := clientConnectWithOldRequest(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 100
			sendSubj := "bar"
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, sendSubj, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			getNext := func(seqno int) {
				t.Helper()
				nextMsg, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error for seq %d: %v", seqno, err)
				}
				if nextMsg.Subject != "bar" {
					t.Fatalf("Expected subject of %q, got %q", "bar", nextMsg.Subject)
				}
				if seq := o.seqFromReply(nextMsg.Reply); seq != uint64(seqno) {
					t.Fatalf("Expected sequence of %d , got %d", seqno, seq)
				}
			}

			// Make sure we can get the messages already there.
			for i := 1; i <= toSend; i++ {
				getNext(i)
			}

			// Now we want to make sure we can get a message that is published to the message
			// set as we are waiting for it.
			nextDelay := 50 * time.Millisecond

			go func() {
				time.Sleep(nextDelay)
				sendStreamMsg(t, nc, sendSubj, "Hello World!")
			}()

			start := time.Now()
			getNext(toSend + 1)
			if time.Since(start) < nextDelay {
				t.Fatalf("Received message too quickly")
			}

			// Now do same thing but combine waiting for new ones with sending.
			go func() {
				time.Sleep(nextDelay)
				for i := 0; i < toSend; i++ {
					nc.Request(sendSubj, []byte("Hello World!"), 50*time.Millisecond)
				}
			}()

			for i := toSend + 2; i < toSend*2+2; i++ {
				getNext(i)
			}
		})
	}
}

func TestJetStreamWorkQueueMaxWaiting(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_MSG_SET", Storage: MemoryStorage, Subjects: []string{"foo", "bar"}}},
		{"FileStore", &StreamConfig{Name: "MY_MSG_SET", Storage: FileStorage, Subjects: []string{"foo", "bar"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			// Make sure these cases fail
			cfg := &ConsumerConfig{Durable: "foo", AckPolicy: AckExplicit, MaxWaiting: 10, DeliverSubject: "_INBOX.22"}
			if _, err := mset.addConsumer(cfg); err == nil {
				t.Fatalf("Expected an error with MaxWaiting set on non-pull based consumer")
			}

			// Create basic work queue mode consumer.
			wcfg := workerModeConfig("MAXWQ")
			o, err := mset.addConsumer(wcfg)
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			// Make sure we set default correctly.
			if cfg := o.config(); cfg.MaxWaiting != JSWaitQueueDefaultMax {
				t.Fatalf("Expected default max waiting to have been set to %d, got %d", JSWaitQueueDefaultMax, cfg.MaxWaiting)
			}

			expectWaiting := func(expected int) {
				t.Helper()
				checkFor(t, time.Second, 25*time.Millisecond, func() error {
					if oi := o.info(); oi.NumWaiting != expected {
						return fmt.Errorf("Expected %d waiting, got %d", expected, oi.NumWaiting)
					}
					return nil
				})
			}

			nc := clientConnectWithOldRequest(t, s)
			defer nc.Close()

			// Like muxed new INBOX.
			sub, _ := nc.SubscribeSync("req.*")
			defer sub.Unsubscribe()
			nc.Flush()

			checkSubPending := func(numExpected int) {
				t.Helper()
				checkFor(t, 200*time.Millisecond, 10*time.Millisecond, func() error {
					if nmsgs, _, err := sub.Pending(); err != nil || nmsgs != numExpected {
						return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, numExpected)
					}
					return nil
				})
			}

			getSubj := o.requestNextMsgSubject()
			// Queue up JSWaitQueueDefaultMax requests.
			for i := 0; i < JSWaitQueueDefaultMax; i++ {
				nc.PublishRequest(getSubj, fmt.Sprintf("req.%d", i), nil)
			}
			expectWaiting(JSWaitQueueDefaultMax)

			// We are at the max, so we should get a 409 saying that we have
			// exceeded the number of pull requests.
			m, err := nc.Request(getSubj, nil, 100*time.Millisecond)
			require_NoError(t, err)
			// Make sure this is the 409
			if v := m.Header.Get("Status"); v != "409" {
				t.Fatalf("Expected a 409 status code, got %q", v)
			}
			// The sub for the other requests should not have received anything
			checkSubPending(0)
			// Now send some messages that should make some of the requests complete
			sendStreamMsg(t, nc, "foo", "Hello World!")
			sendStreamMsg(t, nc, "bar", "Hello World!")
			expectWaiting(JSWaitQueueDefaultMax - 2)
		})
	}
}

func TestJetStreamWorkQueueWrapWaiting(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_MSG_SET", Storage: MemoryStorage, Subjects: []string{"foo", "bar"}}},
		{"FileStore", &StreamConfig{Name: "MY_MSG_SET", Storage: FileStorage, Subjects: []string{"foo", "bar"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			maxWaiting := 8
			wcfg := workerModeConfig("WRAP")
			wcfg.MaxWaiting = maxWaiting

			o, err := mset.addConsumer(wcfg)
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			getSubj := o.requestNextMsgSubject()

			expectWaiting := func(expected int) {
				t.Helper()
				checkFor(t, time.Second, 25*time.Millisecond, func() error {
					if oi := o.info(); oi.NumWaiting != expected {
						return fmt.Errorf("Expected %d waiting, got %d", expected, oi.NumWaiting)
					}
					return nil
				})
			}

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			sub, _ := nc.SubscribeSync("req.*")
			defer sub.Unsubscribe()
			nc.Flush()

			// Fill up waiting.
			for i := 0; i < maxWaiting; i++ {
				nc.PublishRequest(getSubj, fmt.Sprintf("req.%d", i), nil)
			}
			expectWaiting(maxWaiting)

			// Now use 1/2 of the waiting.
			for i := 0; i < maxWaiting/2; i++ {
				sendStreamMsg(t, nc, "foo", "Hello World!")
			}
			expectWaiting(maxWaiting / 2)

			// Now add in two (2) more pull requests.
			for i := maxWaiting; i < maxWaiting+2; i++ {
				nc.PublishRequest(getSubj, fmt.Sprintf("req.%d", i), nil)
			}
			expectWaiting(maxWaiting/2 + 2)

			// Now use second 1/2 of the waiting and the 2 extra.
			for i := 0; i < maxWaiting/2+2; i++ {
				sendStreamMsg(t, nc, "bar", "Hello World!")
			}
			expectWaiting(0)

			checkFor(t, 200*time.Millisecond, 10*time.Millisecond, func() error {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != maxWaiting+2 {
					return fmt.Errorf("Expected sub to have %d pending, got %d", maxWaiting+2, nmsgs)
				}
				return nil
			})
		})
	}
}

func TestJetStreamWorkQueueRequest(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_MSG_SET", Storage: MemoryStorage, Subjects: []string{"foo", "bar"}}},
		{"FileStore", &StreamConfig{Name: "MY_MSG_SET", Storage: FileStorage, Subjects: []string{"foo", "bar"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			o, err := mset.addConsumer(workerModeConfig("WRAP"))
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			toSend := 25
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, "bar", "Hello World!")
			}

			reply := "_.consumer._"
			sub, _ := nc.SubscribeSync(reply)
			defer sub.Unsubscribe()

			getSubj := o.requestNextMsgSubject()

			checkSubPending := func(numExpected int) {
				t.Helper()
				checkFor(t, 200*time.Millisecond, 10*time.Millisecond, func() error {
					if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != numExpected {
						return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, numExpected)
					}
					return nil
				})
			}

			// Create a formal request object.
			req := &JSApiConsumerGetNextRequest{Batch: toSend}
			jreq, _ := json.Marshal(req)
			nc.PublishRequest(getSubj, reply, jreq)

			checkSubPending(toSend)

			// Now check that we can ask for NoWait
			req.Batch = 1
			req.NoWait = true
			jreq, _ = json.Marshal(req)

			resp, err := nc.Request(getSubj, jreq, 100*time.Millisecond)
			require_NoError(t, err)
			if status := resp.Header.Get("Status"); !strings.HasPrefix(status, "404") {
				t.Fatalf("Expected status code of 404")
			}
			// Load up more messages.
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, "foo", "Hello World!")
			}
			// Now we will ask for a batch larger then what is queued up.
			req.Batch = toSend + 10
			req.NoWait = true
			jreq, _ = json.Marshal(req)

			nc.PublishRequest(getSubj, reply, jreq)
			// We should now have 2 * toSend + the 404 message.
			checkSubPending(2*toSend + 1)
			for i := 0; i < 2*toSend+1; i++ {
				sub.NextMsg(time.Millisecond)
			}
			checkSubPending(0)
			mset.purge(nil)

			// Now do expiration
			req.Batch = 1
			req.NoWait = false
			req.Expires = 100 * time.Millisecond
			jreq, _ = json.Marshal(req)

			nc.PublishRequest(getSubj, reply, jreq)
			// Let it expire
			time.Sleep(200 * time.Millisecond)

			// Send a few more messages. These should not be delivered to the sub.
			sendStreamMsg(t, nc, "foo", "Hello World!")
			sendStreamMsg(t, nc, "bar", "Hello World!")
			time.Sleep(100 * time.Millisecond)

			// Expect the request timed out message.
			checkSubPending(1)
			if resp, _ = sub.NextMsg(time.Millisecond); resp == nil {
				t.Fatalf("Expected an expired status message")
			}
			if status := resp.Header.Get("Status"); !strings.HasPrefix(status, "408") {
				t.Fatalf("Expected status code of 408")
			}

			// Send a new request, we should not get the 408 because our previous request
			// should have expired.
			nc.PublishRequest(getSubj, reply, jreq)
			checkSubPending(1)
			sub.NextMsg(time.Second)
			checkSubPending(0)
		})
	}
}

func TestJetStreamSubjectFiltering(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MSET", Storage: MemoryStorage, Subjects: []string{"foo.*"}}},
		{"FileStore", &StreamConfig{Name: "MSET", Storage: FileStorage, Subjects: []string{"foo.*"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			toSend := 50
			subjA := "foo.A"
			subjB := "foo.B"

			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, subjA, "Hello World!")
				sendStreamMsg(t, nc, subjB, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend*2) {
				t.Fatalf("Expected %d messages, got %d", toSend*2, state.Msgs)
			}

			delivery := nats.NewInbox()
			sub, _ := nc.SubscribeSync(delivery)
			defer sub.Unsubscribe()
			nc.Flush()

			o, err := mset.addConsumer(&ConsumerConfig{DeliverSubject: delivery, FilterSubject: subjB})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			// Now let's check the messages
			for i := 1; i <= toSend; i++ {
				m, err := sub.NextMsg(time.Second)
				require_NoError(t, err)
				// JetStream will have the subject match the stream subject, not delivery subject.
				// We want these to only be subjB.
				if m.Subject != subjB {
					t.Fatalf("Expected original subject of %q, but got %q", subjB, m.Subject)
				}
				// Now check that reply subject exists and has a sequence as the last token.
				if seq := o.seqFromReply(m.Reply); seq != uint64(i) {
					t.Fatalf("Expected sequence of %d , got %d", i, seq)
				}
				// Ack the message here.
				m.Respond(nil)
			}

			if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != 0 {
				t.Fatalf("Expected sub to have no pending")
			}
		})
	}
}

func TestJetStreamWorkQueueSubjectFiltering(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_MSG_SET", Storage: MemoryStorage, Subjects: []string{"foo.*"}}},
		{"FileStore", &StreamConfig{Name: "MY_MSG_SET", Storage: FileStorage, Subjects: []string{"foo.*"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			toSend := 50
			subjA := "foo.A"
			subjB := "foo.B"

			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, subjA, "Hello World!")
				sendStreamMsg(t, nc, subjB, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend*2) {
				t.Fatalf("Expected %d messages, got %d", toSend*2, state.Msgs)
			}

			oname := "WQ"
			o, err := mset.addConsumer(&ConsumerConfig{Durable: oname, FilterSubject: subjA, AckPolicy: AckExplicit})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			if o.nextSeq() != 1 {
				t.Fatalf("Expected to be starting at sequence 1")
			}

			getNext := func(seqno int) {
				t.Helper()
				nextMsg, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
				require_NoError(t, err)
				if nextMsg.Subject != subjA {
					t.Fatalf("Expected subject of %q, got %q", subjA, nextMsg.Subject)
				}
				if seq := o.seqFromReply(nextMsg.Reply); seq != uint64(seqno) {
					t.Fatalf("Expected sequence of %d , got %d", seqno, seq)
				}
				nextMsg.Respond(nil)
			}

			// Make sure we can get the messages already there.
			for i := 1; i <= toSend; i++ {
				getNext(i)
			}
		})
	}
}

func TestJetStreamWildcardSubjectFiltering(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "ORDERS", Storage: MemoryStorage, Subjects: []string{"orders.*.*"}}},
		{"FileStore", &StreamConfig{Name: "ORDERS", Storage: FileStorage, Subjects: []string{"orders.*.*"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			toSend := 100
			for i := 1; i <= toSend; i++ {
				subj := fmt.Sprintf("orders.%d.%s", i, "NEW")
				sendStreamMsg(t, nc, subj, "new order")
			}
			// Randomly move 25 to shipped.
			toShip := 25
			shipped := make(map[int]bool)
			for i := 0; i < toShip; {
				orderId := rand.Intn(toSend-1) + 1
				if shipped[orderId] {
					continue
				}
				subj := fmt.Sprintf("orders.%d.%s", orderId, "SHIPPED")
				sendStreamMsg(t, nc, subj, "shipped order")
				shipped[orderId] = true
				i++
			}
			state := mset.state()
			if state.Msgs != uint64(toSend+toShip) {
				t.Fatalf("Expected %d messages, got %d", toSend+toShip, state.Msgs)
			}

			delivery := nats.NewInbox()
			sub, _ := nc.SubscribeSync(delivery)
			defer sub.Unsubscribe()
			nc.Flush()

			// Get all shipped.
			o, err := mset.addConsumer(&ConsumerConfig{DeliverSubject: delivery, FilterSubject: "orders.*.SHIPPED"})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			checkFor(t, time.Second, 25*time.Millisecond, func() error {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != toShip {
					return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, toShip)
				}
				return nil
			})
			for nmsgs, _, _ := sub.Pending(); nmsgs > 0; nmsgs, _, _ = sub.Pending() {
				sub.NextMsg(time.Second)
			}
			if nmsgs, _, _ := sub.Pending(); nmsgs != 0 {
				t.Fatalf("Expected no pending, got %d", nmsgs)
			}

			// Get all new
			o, err = mset.addConsumer(&ConsumerConfig{DeliverSubject: delivery, FilterSubject: "orders.*.NEW"})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			checkFor(t, time.Second, 25*time.Millisecond, func() error {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != toSend {
					return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, toSend)
				}
				return nil
			})
			for nmsgs, _, _ := sub.Pending(); nmsgs > 0; nmsgs, _, _ = sub.Pending() {
				sub.NextMsg(time.Second)
			}
			if nmsgs, _, _ := sub.Pending(); nmsgs != 0 {
				t.Fatalf("Expected no pending, got %d", nmsgs)
			}

			// Now grab a single orderId that has shipped, so we should have two messages.
			var orderId int
			for orderId = range shipped {
				break
			}
			subj := fmt.Sprintf("orders.%d.*", orderId)
			o, err = mset.addConsumer(&ConsumerConfig{DeliverSubject: delivery, FilterSubject: subj})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			checkFor(t, time.Second, 25*time.Millisecond, func() error {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != 2 {
					return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, 2)
				}
				return nil
			})
		})
	}
}

func TestJetStreamWorkQueueAckAndNext(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_MSG_SET", Storage: MemoryStorage, Subjects: []string{"foo", "bar"}}},
		{"FileStore", &StreamConfig{Name: "MY_MSG_SET", Storage: FileStorage, Subjects: []string{"foo", "bar"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			// Create basic work queue mode consumer.
			oname := "WQ"
			o, err := mset.addConsumer(workerModeConfig(oname))
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			if o.nextSeq() != 1 {
				t.Fatalf("Expected to be starting at sequence 1")
			}

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 100
			sendSubj := "bar"
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, sendSubj, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			sub, _ := nc.SubscribeSync(nats.NewInbox())
			defer sub.Unsubscribe()

			// Kick things off.
			// For normal work queue semantics, you send requests to the subject with stream and consumer name.
			// We will do this to start it off then use ack+next to get other messages.
			nc.PublishRequest(o.requestNextMsgSubject(), sub.Subject, nil)

			for i := 0; i < toSend; i++ {
				m, err := sub.NextMsg(time.Second)
				if err != nil {
					t.Fatalf("Unexpected error waiting for messages: %v", err)
				}

				if !bytes.Equal(m.Data, []byte("Hello World!")) {
					t.Fatalf("Got an invalid message from the stream: %q", m.Data)
				}

				nc.PublishRequest(m.Reply, sub.Subject, AckNext)
			}
		})
	}
}

func TestJetStreamWorkQueueRequestBatch(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_MSG_SET", Storage: MemoryStorage, Subjects: []string{"foo", "bar"}}},
		{"FileStore", &StreamConfig{Name: "MY_MSG_SET", Storage: FileStorage, Subjects: []string{"foo", "bar"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			// Create basic work queue mode consumer.
			oname := "WQ"
			o, err := mset.addConsumer(workerModeConfig(oname))
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			if o.nextSeq() != 1 {
				t.Fatalf("Expected to be starting at sequence 1")
			}

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 100
			sendSubj := "bar"
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, sendSubj, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			sub, _ := nc.SubscribeSync(nats.NewInbox())
			defer sub.Unsubscribe()

			// For normal work queue semantics, you send requests to the subject with stream and consumer name.
			// We will do this to start it off then use ack+next to get other messages.
			// Kick things off with batch size of 50.
			batchSize := 50
			nc.PublishRequest(o.requestNextMsgSubject(), sub.Subject, []byte(strconv.Itoa(batchSize)))

			// We should receive batchSize with no acks or additional requests.
			checkFor(t, 250*time.Millisecond, 10*time.Millisecond, func() error {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != batchSize {
					return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, batchSize)
				}
				return nil
			})

			// Now queue up the request without messages and add them after.
			sub, _ = nc.SubscribeSync(nats.NewInbox())
			defer sub.Unsubscribe()
			mset.purge(nil)

			nc.PublishRequest(o.requestNextMsgSubject(), sub.Subject, []byte(strconv.Itoa(batchSize)))
			nc.Flush() // Make sure its registered.

			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, sendSubj, "Hello World!")
			}

			// We should receive batchSize with no acks or additional requests.
			checkFor(t, 250*time.Millisecond, 10*time.Millisecond, func() error {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != batchSize {
					return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, batchSize)
				}
				return nil
			})
		})
	}
}

func TestJetStreamWorkQueueRetentionStream(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{name: "MemoryStore", mconfig: &StreamConfig{
			Name:      "MWQ",
			Storage:   MemoryStorage,
			Subjects:  []string{"MY_WORK_QUEUE.>"},
			Retention: WorkQueuePolicy},
		},
		{name: "FileStore", mconfig: &StreamConfig{
			Name:      "MWQ",
			Storage:   FileStorage,
			Subjects:  []string{"MY_WORK_QUEUE.>"},
			Retention: WorkQueuePolicy},
		},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			// This type of stream has restrictions which we will test here.
			// DeliverAll is only start mode allowed.
			if _, err := mset.addConsumer(&ConsumerConfig{DeliverPolicy: DeliverLast}); err == nil {
				t.Fatalf("Expected an error with anything but DeliverAll")
			}

			// We will create a non-partitioned consumer. This should succeed.
			o, err := mset.addConsumer(&ConsumerConfig{Durable: "PBO", AckPolicy: AckExplicit})
			require_NoError(t, err)
			defer o.delete()

			// Now if we create another this should fail, only can have one non-partitioned.
			if _, err := mset.addConsumer(&ConsumerConfig{}); err == nil {
				t.Fatalf("Expected an error on attempt for second consumer for a workqueue")
			}
			o.delete()

			if numo := mset.numConsumers(); numo != 0 {
				t.Fatalf("Expected to have zero consumers, got %d", numo)
			}

			// Now add in an consumer that has a partition.
			pindex := 1
			pConfig := func(pname string) *ConsumerConfig {
				dname := fmt.Sprintf("PPBO-%d", pindex)
				pindex += 1
				return &ConsumerConfig{Durable: dname, FilterSubject: pname, AckPolicy: AckExplicit}
			}
			o, err = mset.addConsumer(pConfig("MY_WORK_QUEUE.A"))
			require_NoError(t, err)
			defer o.delete()

			// Now creating another with separate partition should work.
			o2, err := mset.addConsumer(pConfig("MY_WORK_QUEUE.B"))
			require_NoError(t, err)
			defer o2.delete()

			// Anything that would overlap should fail though.
			if _, err := mset.addConsumer(pConfig("MY_WORK_QUEUE.A")); err == nil {
				t.Fatalf("Expected an error on attempt for partitioned consumer for a workqueue")
			}
			if _, err := mset.addConsumer(pConfig("MY_WORK_QUEUE.B")); err == nil {
				t.Fatalf("Expected an error on attempt for partitioned consumer for a workqueue")
			}

			o3, err := mset.addConsumer(pConfig("MY_WORK_QUEUE.C"))
			require_NoError(t, err)

			o.delete()
			o2.delete()
			o3.delete()

			// Test with wildcards, first from wider to narrower
			o, err = mset.addConsumer(pConfig("MY_WORK_QUEUE.>"))
			require_NoError(t, err)
			if _, err := mset.addConsumer(pConfig("MY_WORK_QUEUE.*.BAR")); err == nil {
				t.Fatalf("Expected an error on attempt for partitioned consumer for a workqueue")
			}
			o.delete()

			// Now from narrower to wider
			o, err = mset.addConsumer(pConfig("MY_WORK_QUEUE.*.BAR"))
			require_NoError(t, err)
			if _, err := mset.addConsumer(pConfig("MY_WORK_QUEUE.>")); err == nil {
				t.Fatalf("Expected an error on attempt for partitioned consumer for a workqueue")
			}
			o.delete()

			// Push based will be allowed now, including ephemerals.
			// They can not overlap etc meaning same rules as above apply.
			o4, err := mset.addConsumer(&ConsumerConfig{
				Durable:        "DURABLE",
				DeliverSubject: "SOME.SUBJ",
				AckPolicy:      AckExplicit,
			})
			if err != nil {
				t.Fatalf("Unexpected Error: %v", err)
			}
			defer o4.delete()

			// Now try to create an ephemeral
			nc := clientConnectToServer(t, s)
			defer nc.Close()

			sub, _ := nc.SubscribeSync(nats.NewInbox())
			defer sub.Unsubscribe()
			nc.Flush()

			// This should fail at first due to conflict above.
			ephCfg := &ConsumerConfig{DeliverSubject: sub.Subject, AckPolicy: AckExplicit}
			if _, err := mset.addConsumer(ephCfg); err == nil {
				t.Fatalf("Expected an error ")
			}
			// Delete of o4 should clear.
			o4.delete()
			o5, err := mset.addConsumer(ephCfg)
			if err != nil {
				t.Fatalf("Unexpected Error: %v", err)
			}
			defer o5.delete()
		})
	}
}

func TestJetStreamAckAllRedelivery(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_S22", Storage: MemoryStorage}},
		{"FileStore", &StreamConfig{Name: "MY_S22", Storage: FileStorage}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 100
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, c.mconfig.Name, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			sub, _ := nc.SubscribeSync(nats.NewInbox())
			defer sub.Unsubscribe()
			nc.Flush()

			o, err := mset.addConsumer(&ConsumerConfig{
				DeliverSubject: sub.Subject,
				AckWait:        50 * time.Millisecond,
				AckPolicy:      AckAll,
			})
			if err != nil {
				t.Fatalf("Unexpected error adding consumer: %v", err)
			}
			defer o.delete()

			// Wait for messages.
			// We will do 5 redeliveries.
			for i := 1; i <= 5; i++ {
				checkFor(t, 500*time.Millisecond, 10*time.Millisecond, func() error {
					if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != toSend*i {
						return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, toSend*i)
					}
					return nil
				})
			}
			// Stop redeliveries.
			o.delete()

			// Now make sure that they are all redelivered in order for each redelivered batch.
			for l := 1; l <= 5; l++ {
				for i := 1; i <= toSend; i++ {
					m, _ := sub.NextMsg(time.Second)
					if seq := o.streamSeqFromReply(m.Reply); seq != uint64(i) {
						t.Fatalf("Expected stream sequence of %d, got %d", i, seq)
					}
				}
			}
		})
	}
}

func TestJetStreamAckReplyStreamPending(t *testing.T) {
	msc := StreamConfig{
		Name:      "MY_WQ",
		Subjects:  []string{"foo.*"},
		Storage:   MemoryStorage,
		MaxAge:    1 * time.Second,
		Retention: WorkQueuePolicy,
	}
	fsc := msc
	fsc.Storage = FileStorage

	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &msc},
		{"FileStore", &fsc},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 100
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, "foo.1", "Hello World!")
			}
			nc.Flush()

			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			o, err := mset.addConsumer(&ConsumerConfig{Durable: "PBO", AckPolicy: AckExplicit})
			require_NoError(t, err)
			defer o.delete()

			expectPending := func(ep int) {
				t.Helper()
				// Now check consumer info.
				checkFor(t, time.Second, 10*time.Millisecond, func() error {
					if info, pep := o.info(), ep+1; int(info.NumPending) != pep {
						return fmt.Errorf("Expected consumer info pending of %d, got %d", pep, info.NumPending)
					}
					return nil
				})
				m, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				_, _, _, _, pending := replyInfo(m.Reply)
				if pending != uint64(ep) {
					t.Fatalf("Expected ack reply pending of %d, got %d - reply: %q", ep, pending, m.Reply)
				}
			}

			expectPending(toSend - 1)
			// Send some more while we are connected.
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, "foo.1", "Hello World!")
			}
			nc.Flush()

			expectPending(toSend*2 - 2)
			// Purge and send a new one.
			mset.purge(nil)
			nc.Flush()

			sendStreamMsg(t, nc, "foo.1", "Hello World!")
			expectPending(0)
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, "foo.22", "Hello World!")
			}
			expectPending(toSend - 1) // 201
			// Test that delete will not register for consumed messages.
			mset.removeMsg(mset.state().FirstSeq)
			expectPending(toSend - 2) // 202
			// Now remove one that has not been delivered.
			mset.removeMsg(250)
			expectPending(toSend - 4) // 203

			// Test Expiration.
			mset.purge(nil)
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, "foo.1", "Hello World!")
			}
			nc.Flush()

			// Wait for expiration to kick in.
			checkFor(t, 5*time.Second, time.Second, func() error {
				if state := mset.state(); state.Msgs != 0 {
					return fmt.Errorf("Stream still has messages")
				}
				return nil
			})
			sendStreamMsg(t, nc, "foo.33", "Hello World!")
			expectPending(0)

			// Now do filtered consumers.
			o.delete()
			o, err = mset.addConsumer(&ConsumerConfig{Durable: "PBO-FILTERED", AckPolicy: AckExplicit, FilterSubject: "foo.22"})
			require_NoError(t, err)
			defer o.delete()

			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, "foo.33", "Hello World!")
			}
			nc.Flush()

			if info := o.info(); info.NumPending != 0 {
				t.Fatalf("Expected no pending, got %d", info.NumPending)
			}
			// Now send one message that will match us.
			sendStreamMsg(t, nc, "foo.22", "Hello World!")
			expectPending(0)
			sendStreamMsg(t, nc, "foo.22", "Hello World!") // 504
			sendStreamMsg(t, nc, "foo.22", "Hello World!") // 505
			sendStreamMsg(t, nc, "foo.22", "Hello World!") // 506
			sendStreamMsg(t, nc, "foo.22", "Hello World!") // 507
			expectPending(3)
			mset.removeMsg(506)
			expectPending(1)
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, "foo.22", "Hello World!")
			}
			nc.Flush()
			expectPending(100)
			mset.purge(nil)
			sendStreamMsg(t, nc, "foo.22", "Hello World!")
			expectPending(0)
		})
	}
}

func TestJetStreamAckReplyStreamPendingWithAcks(t *testing.T) {
	msc := StreamConfig{
		Name:     "MY_STREAM",
		Subjects: []string{"foo", "bar", "baz"},
		Storage:  MemoryStorage,
	}
	fsc := msc
	fsc.Storage = FileStorage

	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &msc},
		{"FileStore", &fsc},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 500
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, "foo", "Hello Foo!")
				sendStreamMsg(t, nc, "bar", "Hello Bar!")
				sendStreamMsg(t, nc, "baz", "Hello Baz!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend*3) {
				t.Fatalf("Expected %d messages, got %d", toSend*3, state.Msgs)
			}
			dsubj := "_d_"
			o, err := mset.addConsumer(&ConsumerConfig{
				Durable:        "D-1",
				AckPolicy:      AckExplicit,
				FilterSubject:  "foo",
				DeliverSubject: dsubj,
			})
			require_NoError(t, err)
			defer o.delete()

			if info := o.info(); int(info.NumPending) != toSend {
				t.Fatalf("Expected consumer info pending of %d, got %d", toSend, info.NumPending)
			}

			sub, _ := nc.SubscribeSync(dsubj)
			defer sub.Unsubscribe()

			checkFor(t, 500*time.Millisecond, 10*time.Millisecond, func() error {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != toSend {
					return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, toSend)
				}
				return nil
			})

			// Should be zero.
			if info := o.info(); int(info.NumPending) != 0 {
				t.Fatalf("Expected consumer info pending of %d, got %d", 0, info.NumPending)
			} else if info.NumAckPending != toSend {
				t.Fatalf("Expected %d to be pending acks, got %d", toSend, info.NumAckPending)
			}
		})
	}
}

func TestJetStreamWorkQueueAckWaitRedelivery(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_WQ", Storage: MemoryStorage, Retention: WorkQueuePolicy}},
		{"FileStore", &StreamConfig{Name: "MY_WQ", Storage: FileStorage, Retention: WorkQueuePolicy}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 100
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, c.mconfig.Name, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			ackWait := 100 * time.Millisecond

			o, err := mset.addConsumer(&ConsumerConfig{Durable: "PBO", AckPolicy: AckExplicit, AckWait: ackWait})
			require_NoError(t, err)
			defer o.delete()

			sub, _ := nc.SubscribeSync(nats.NewInbox())
			defer sub.Unsubscribe()

			reqNextMsgSubj := o.requestNextMsgSubject()

			// Consume all the messages. But do not ack.
			for i := 0; i < toSend; i++ {
				nc.PublishRequest(reqNextMsgSubj, sub.Subject, nil)
				if _, err := sub.NextMsg(time.Second); err != nil {
					t.Fatalf("Unexpected error waiting for messages: %v", err)
				}
			}

			if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != 0 {
				t.Fatalf("Did not consume all messages, still have %d", nmsgs)
			}

			// All messages should still be there.
			state = mset.state()
			if int(state.Msgs) != toSend {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			// Now consume and ack.
			for i := 1; i <= toSend; i++ {
				nc.PublishRequest(reqNextMsgSubj, sub.Subject, nil)
				m, err := sub.NextMsg(time.Second)
				if err != nil {
					t.Fatalf("Unexpected error waiting for message[%d]: %v", i, err)
				}
				sseq, dseq, dcount, _, _ := replyInfo(m.Reply)
				if sseq != uint64(i) {
					t.Fatalf("Expected set sequence of %d , got %d", i, sseq)
				}
				// Delivery sequences should always increase.
				if dseq != uint64(toSend+i) {
					t.Fatalf("Expected delivery sequence of %d , got %d", toSend+i, dseq)
				}
				if dcount == 1 {
					t.Fatalf("Expected these to be marked as redelivered")
				}
				// Ack the message here.
				m.AckSync()
			}

			if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != 0 {
				t.Fatalf("Did not consume all messages, still have %d", nmsgs)
			}

			// Flush acks
			nc.Flush()

			// Now check the mset as well, since we have a WorkQueue retention policy this should be empty.
			if state := mset.state(); state.Msgs != 0 {
				t.Fatalf("Expected no messages, got %d", state.Msgs)
			}
		})
	}
}

func TestJetStreamWorkQueueNakRedelivery(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_WQ", Storage: MemoryStorage, Retention: WorkQueuePolicy}},
		{"FileStore", &StreamConfig{Name: "MY_WQ", Storage: FileStorage, Retention: WorkQueuePolicy}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 10
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, c.mconfig.Name, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			o, err := mset.addConsumer(&ConsumerConfig{Durable: "PBO", AckPolicy: AckExplicit})
			require_NoError(t, err)
			defer o.delete()

			getMsg := func(sseq, dseq int) *nats.Msg {
				t.Helper()
				m, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				rsseq, rdseq, _, _, _ := replyInfo(m.Reply)
				if rdseq != uint64(dseq) {
					t.Fatalf("Expected delivered sequence of %d , got %d", dseq, rdseq)
				}
				if rsseq != uint64(sseq) {
					t.Fatalf("Expected store sequence of %d , got %d", sseq, rsseq)
				}
				return m
			}

			for i := 1; i <= 5; i++ {
				m := getMsg(i, i)
				// Ack the message here.
				m.Respond(nil)
			}

			// Grab #6
			m := getMsg(6, 6)
			// NAK this one and make sure its processed.
			m.Respond(AckNak)
			nc.Flush()

			// When we request again should be store sequence 6 again.
			getMsg(6, 7)
			// Then we should get 7, 8, etc.
			getMsg(7, 8)
			getMsg(8, 9)
		})
	}
}

func TestJetStreamWorkQueueWorkingIndicator(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_WQ", Storage: MemoryStorage, Retention: WorkQueuePolicy}},
		{"FileStore", &StreamConfig{Name: "MY_WQ", Storage: FileStorage, Retention: WorkQueuePolicy}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 2
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, c.mconfig.Name, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			ackWait := 100 * time.Millisecond

			o, err := mset.addConsumer(&ConsumerConfig{Durable: "PBO", AckPolicy: AckExplicit, AckWait: ackWait})
			require_NoError(t, err)
			defer o.delete()

			getMsg := func(sseq, dseq int) *nats.Msg {
				t.Helper()
				m, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				rsseq, rdseq, _, _, _ := replyInfo(m.Reply)
				if rdseq != uint64(dseq) {
					t.Fatalf("Expected delivered sequence of %d , got %d", dseq, rdseq)
				}
				if rsseq != uint64(sseq) {
					t.Fatalf("Expected store sequence of %d , got %d", sseq, rsseq)
				}
				return m
			}

			getMsg(1, 1)
			// Now wait past ackWait
			time.Sleep(ackWait * 2)

			// We should get 1 back.
			m := getMsg(1, 2)

			// Now let's take longer than ackWait to process but signal we are working on the message.
			timeout := time.Now().Add(3 * ackWait)
			for time.Now().Before(timeout) {
				m.Respond(AckProgress)
				nc.Flush()
				time.Sleep(ackWait / 5)
			}
			// We should get 2 here, not 1 since we have indicated we are working on it.
			m2 := getMsg(2, 3)
			time.Sleep(ackWait / 2)
			m2.Respond(AckProgress)

			// Now should get 1 back then 2.
			m = getMsg(1, 4)
			m.Respond(nil)
			getMsg(2, 5)
		})
	}
}

func TestJetStreamWorkQueueTerminateDelivery(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "MY_WQ", Storage: MemoryStorage, Retention: WorkQueuePolicy}},
		{"FileStore", &StreamConfig{Name: "MY_WQ", Storage: FileStorage, Retention: WorkQueuePolicy}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 22
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, c.mconfig.Name, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			ackWait := 25 * time.Millisecond

			o, err := mset.addConsumer(&ConsumerConfig{Durable: "PBO", AckPolicy: AckExplicit, AckWait: ackWait})
			require_NoError(t, err)
			defer o.delete()

			getMsg := func(sseq, dseq int) *nats.Msg {
				t.Helper()
				m, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				rsseq, rdseq, _, _, _ := replyInfo(m.Reply)
				if rdseq != uint64(dseq) {
					t.Fatalf("Expected delivered sequence of %d , got %d", dseq, rdseq)
				}
				if rsseq != uint64(sseq) {
					t.Fatalf("Expected store sequence of %d , got %d", sseq, rsseq)
				}
				return m
			}

			// Make sure we get the correct advisory
			sub, _ := nc.SubscribeSync(JSAdvisoryConsumerMsgTerminatedPre + ".>")
			defer sub.Unsubscribe()

			getMsg(1, 1)
			// Now wait past ackWait
			time.Sleep(ackWait * 2)

			// We should get 1 back.
			m := getMsg(1, 2)
			// Now terminate
			m.Respond([]byte(fmt.Sprintf("%s with reason", string(AckTerm))))
			time.Sleep(ackWait * 2)

			// We should get 2 here, not 1 since we have indicated we wanted to terminate.
			getMsg(2, 3)

			// Check advisory was delivered.
			am, err := sub.NextMsg(time.Second)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			var adv JSConsumerDeliveryTerminatedAdvisory
			json.Unmarshal(am.Data, &adv)
			if adv.Stream != "MY_WQ" {
				t.Fatalf("Expected stream of %s, got %s", "MY_WQ", adv.Stream)
			}
			if adv.Consumer != "PBO" {
				t.Fatalf("Expected consumer of %s, got %s", "PBO", adv.Consumer)
			}
			if adv.StreamSeq != 1 {
				t.Fatalf("Expected stream sequence of %d, got %d", 1, adv.StreamSeq)
			}
			if adv.ConsumerSeq != 2 {
				t.Fatalf("Expected consumer sequence of %d, got %d", 2, adv.ConsumerSeq)
			}
			if adv.Deliveries != 2 {
				t.Fatalf("Expected delivery count of %d, got %d", 2, adv.Deliveries)
			}
			if adv.Reason != "with reason" {
				t.Fatalf("Advisory did not have a reason")
			}
		})
	}
}

func TestJetStreamAckNext(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	mname := "ACKNXT"
	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: mname, Storage: MemoryStorage})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	o, err := mset.addConsumer(&ConsumerConfig{Durable: "worker", AckPolicy: AckExplicit})
	if err != nil {
		t.Fatalf("Expected no error with registered interest, got %v", err)
	}
	defer o.delete()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	for i := 0; i < 12; i++ {
		sendStreamMsg(t, nc, mname, fmt.Sprintf("msg %d", i))
	}

	q := make(chan *nats.Msg, 10)
	sub, err := nc.ChanSubscribe(nats.NewInbox(), q)
	if err != nil {
		t.Fatalf("SubscribeSync failed: %s", err)
	}

	nc.PublishRequest(o.requestNextMsgSubject(), sub.Subject, []byte("1"))

	// normal next should imply 1
	msg := <-q
	err = msg.RespondMsg(&nats.Msg{Reply: sub.Subject, Subject: msg.Reply, Data: AckNext})
	if err != nil {
		t.Fatalf("RespondMsg failed: %s", err)
	}

	// read 1 message and check ack was done etc
	msg = <-q
	if len(q) != 0 {
		t.Fatalf("Expected empty q got %d", len(q))
	}
	if o.info().AckFloor.Stream != 1 {
		t.Fatalf("First message was not acknowledged")
	}
	if !bytes.Equal(msg.Data, []byte("msg 1")) {
		t.Fatalf("wrong message received, expected: msg 1 got %q", msg.Data)
	}

	// now ack and request 5 more using a naked number
	err = msg.RespondMsg(&nats.Msg{Reply: sub.Subject, Subject: msg.Reply, Data: append(AckNext, []byte(" 5")...)})
	if err != nil {
		t.Fatalf("RespondMsg failed: %s", err)
	}

	getMsgs := func(start, count int) {
		t.Helper()

		ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
		defer cancel()

		for i := start; i < count+1; i++ {
			select {
			case msg := <-q:
				expect := fmt.Sprintf("msg %d", i+1)
				if !bytes.Equal(msg.Data, []byte(expect)) {
					t.Fatalf("wrong message received, expected: %s got %#v", expect, msg)
				}
			case <-ctx.Done():
				t.Fatalf("did not receive all messages")
			}
		}

	}

	getMsgs(1, 5)

	// now ack and request 5 more using the full request
	err = msg.RespondMsg(&nats.Msg{Reply: sub.Subject, Subject: msg.Reply, Data: append(AckNext, []byte(`{"batch": 5}`)...)})
	if err != nil {
		t.Fatalf("RespondMsg failed: %s", err)
	}

	getMsgs(6, 10)

	if o.info().AckFloor.Stream != 2 {
		t.Fatalf("second message was not acknowledged")
	}
}

func TestJetStreamPublishDeDupe(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	mname := "DeDupe"
	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: mname, Storage: FileStorage, MaxAge: time.Hour, Subjects: []string{"foo.*"}})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	// Check Duplicates setting.
	duplicates := mset.config().Duplicates
	if duplicates != StreamDefaultDuplicatesWindow {
		t.Fatalf("Expected a default of %v, got %v", StreamDefaultDuplicatesWindow, duplicates)
	}

	cfg := mset.config()
	// Make sure can't be negative.
	cfg.Duplicates = -25 * time.Millisecond
	if err := mset.update(&cfg); err == nil {
		t.Fatalf("Expected an error but got none")
	}
	// Make sure can't be longer than age if its set.
	cfg.Duplicates = 2 * time.Hour
	if err := mset.update(&cfg); err == nil {
		t.Fatalf("Expected an error but got none")
	}

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	sendMsg := func(seq uint64, id, msg string) *PubAck {
		t.Helper()
		m := nats.NewMsg(fmt.Sprintf("foo.%d", seq))
		m.Header.Add(JSMsgId, id)
		m.Data = []byte(msg)
		resp, _ := nc.RequestMsg(m, 100*time.Millisecond)
		if resp == nil {
			t.Fatalf("No response for %q, possible timeout?", msg)
		}
		pa := getPubAckResponse(resp.Data)
		if pa == nil || pa.Error != nil {
			t.Fatalf("Expected a JetStreamPubAck, got %q", resp.Data)
		}
		if pa.Sequence != seq {
			t.Fatalf("Did not get correct sequence in PubAck, expected %d, got %d", seq, pa.Sequence)
		}
		return pa.PubAck
	}

	expect := func(n uint64) {
		t.Helper()
		state := mset.state()
		if state.Msgs != n {
			t.Fatalf("Expected %d messages, got %d", n, state.Msgs)
		}
	}

	sendMsg(1, "AA", "Hello DeDupe!")
	sendMsg(2, "BB", "Hello DeDupe!")
	sendMsg(3, "CC", "Hello DeDupe!")
	sendMsg(4, "ZZ", "Hello DeDupe!")
	expect(4)

	sendMsg(1, "AA", "Hello DeDupe!")
	sendMsg(2, "BB", "Hello DeDupe!")
	sendMsg(4, "ZZ", "Hello DeDupe!")
	expect(4)

	cfg = mset.config()
	cfg.Duplicates = 100 * time.Millisecond
	if err := mset.update(&cfg); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	nmids := func(expected int) {
		t.Helper()
		checkFor(t, 200*time.Millisecond, 10*time.Millisecond, func() error {
			if nids := mset.numMsgIds(); nids != expected {
				return fmt.Errorf("Expected %d message ids, got %d", expected, nids)
			}
			return nil
		})
	}

	nmids(4)
	time.Sleep(cfg.Duplicates * 2)

	sendMsg(5, "AAA", "Hello DeDupe!")
	sendMsg(6, "BBB", "Hello DeDupe!")
	sendMsg(7, "CCC", "Hello DeDupe!")
	sendMsg(8, "DDD", "Hello DeDupe!")
	sendMsg(9, "ZZZ", "Hello DeDupe!")
	nmids(5)
	// Eventually will drop to zero.
	nmids(0)

	// Now test server restart
	cfg.Duplicates = 30 * time.Minute
	if err := mset.update(&cfg); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	mset.purge(nil)

	// Send 5 new messages.
	sendMsg(10, "AAAA", "Hello DeDupe!")
	sendMsg(11, "BBBB", "Hello DeDupe!")
	sendMsg(12, "CCCC", "Hello DeDupe!")
	sendMsg(13, "DDDD", "Hello DeDupe!")
	sendMsg(14, "EEEE", "Hello DeDupe!")

	// Stop current
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	// Restart.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc = clientConnectToServer(t, s)
	defer nc.Close()

	mset, _ = s.GlobalAccount().lookupStream(mname)
	if nms := mset.state().Msgs; nms != 5 {
		t.Fatalf("Expected 5 restored messages, got %d", nms)
	}
	nmids(5)

	// Send same and make sure duplicate detection still works.
	// Send 5 duplicate messages.
	sendMsg(10, "AAAA", "Hello DeDupe!")
	sendMsg(11, "BBBB", "Hello DeDupe!")
	sendMsg(12, "CCCC", "Hello DeDupe!")
	sendMsg(13, "DDDD", "Hello DeDupe!")
	sendMsg(14, "EEEE", "Hello DeDupe!")

	if nms := mset.state().Msgs; nms != 5 {
		t.Fatalf("Expected 5 restored messages, got %d", nms)
	}
	nmids(5)

	// Check we set duplicate properly.
	pa := sendMsg(10, "AAAA", "Hello DeDupe!")
	if !pa.Duplicate {
		t.Fatalf("Expected duplicate to be set")
	}

	// Purge should NOT wipe the msgIds. They should still persist.
	mset.purge(nil)
	nmids(5)
}

func getPubAckResponse(msg []byte) *JSPubAckResponse {
	var par JSPubAckResponse
	if err := json.Unmarshal(msg, &par); err != nil {
		return nil
	}
	return &par
}

func TestJetStreamPublishExpect(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	mname := "EXPECT"
	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: mname, Storage: FileStorage, MaxAge: time.Hour, Subjects: []string{"foo.*"}})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	// Test that we get no error when expected stream is correct.
	m := nats.NewMsg("foo.bar")
	m.Data = []byte("HELLO")
	m.Header.Set(JSExpectedStream, mname)
	resp, err := nc.RequestMsg(m, 100*time.Millisecond)
	require_NoError(t, err)
	if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error != nil {
		t.Fatalf("Expected a valid JetStreamPubAck, got %q", resp.Data)
	}

	// Now test that we get an error back when expecting a different stream.
	m.Header.Set(JSExpectedStream, "ORDERS")
	resp, err = nc.RequestMsg(m, 100*time.Millisecond)
	require_NoError(t, err)
	if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error == nil {
		t.Fatalf("Expected an error, got %q", resp.Data)
	}

	// Now test that we get an error back when expecting a different sequence number.
	m.Header.Set(JSExpectedStream, mname)
	m.Header.Set(JSExpectedLastSeq, "10")
	resp, err = nc.RequestMsg(m, 100*time.Millisecond)
	require_NoError(t, err)
	if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error == nil {
		t.Fatalf("Expected an error, got %q", resp.Data)
	}

	// Or if we expect that there are no messages by setting "0" as the expected last seq
	m.Header.Set(JSExpectedLastSeq, "0")
	resp, err = nc.RequestMsg(m, 100*time.Millisecond)
	require_NoError(t, err)
	if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error == nil {
		t.Fatalf("Expected an error, got %q", resp.Data)
	}

	// Now send a message with a message ID and make sure we can match that.
	m = nats.NewMsg("foo.bar")
	m.Data = []byte("HELLO")
	m.Header.Set(JSMsgId, "AAA")
	if _, err = nc.RequestMsg(m, 100*time.Millisecond); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// Now try again with new message ID but require last one to be 'BBB'
	m.Header.Set(JSMsgId, "ZZZ")
	m.Header.Set(JSExpectedLastMsgId, "BBB")
	resp, err = nc.RequestMsg(m, 100*time.Millisecond)
	require_NoError(t, err)
	if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error == nil {
		t.Fatalf("Expected an error, got %q", resp.Data)
	}

	// Restart the server and make sure we remember/rebuild last seq and last msgId.
	// Stop current
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	// Restart.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc = clientConnectToServer(t, s)
	defer nc.Close()

	// Our last sequence was 2 and last msgId was "AAA"
	m = nats.NewMsg("foo.baz")
	m.Data = []byte("HELLO AGAIN")
	m.Header.Set(JSExpectedLastSeq, "2")
	m.Header.Set(JSExpectedLastMsgId, "AAA")
	m.Header.Set(JSMsgId, "BBB")
	resp, err = nc.RequestMsg(m, 100*time.Millisecond)
	require_NoError(t, err)
	if pa := getPubAckResponse(resp.Data); pa == nil || pa.Error != nil {
		t.Fatalf("Expected a valid JetStreamPubAck, got %q", resp.Data)
	}
}

func TestJetStreamRedeliveryAfterServerRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	sendSubj := "MYQ"
	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: sendSubj, Storage: FileStorage})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	// Now load up some messages.
	toSend := 25
	for i := 0; i < toSend; i++ {
		sendStreamMsg(t, nc, sendSubj, "Hello World!")
	}
	state := mset.state()
	if state.Msgs != uint64(toSend) {
		t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
	}

	sub, _ := nc.SubscribeSync(nats.NewInbox())
	defer sub.Unsubscribe()
	nc.Flush()

	o, err := mset.addConsumer(&ConsumerConfig{
		Durable:        "TO",
		DeliverSubject: sub.Subject,
		AckPolicy:      AckExplicit,
		AckWait:        100 * time.Millisecond,
	})
	require_NoError(t, err)
	defer o.delete()

	checkFor(t, 250*time.Millisecond, 10*time.Millisecond, func() error {
		if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != toSend {
			return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, toSend)
		}
		return nil
	})

	// Capture port since it was dynamic.
	u, _ := url.Parse(s.ClientURL())
	port, _ := strconv.Atoi(u.Port())
	sd := s.JetStreamConfig().StoreDir

	// Stop current
	s.Shutdown()

	// Restart.
	s = RunJetStreamServerOnPort(port, sd)
	defer s.Shutdown()

	// Don't wait for reconnect from old client.
	nc = clientConnectToServer(t, s)
	defer nc.Close()

	sub, _ = nc.SubscribeSync(sub.Subject)
	defer sub.Unsubscribe()

	checkFor(t, time.Second, 50*time.Millisecond, func() error {
		if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != toSend {
			return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, toSend)
		}
		return nil
	})
}

func TestJetStreamUsageNoReservation(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", replicas)
			defer c.shutdown()
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		_, err := js.AddStream(&nats.StreamConfig{Name: "FILE", Storage: nats.FileStorage, Replicas: replicas})
		require_NoError(t, err)
		_, err = js.AddStream(&nats.StreamConfig{Name: "MEM", Storage: nats.MemoryStorage, Replicas: replicas})
		require_NoError(t, err)

		acc := s.globalAccount()
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			if streams := acc.numStreams(); streams != 2 {
				return fmt.Errorf("not at 2 streams yet, got %d", streams)
			}
			return nil
		})

		stats := acc.JetStreamUsage()
		require_Equal(t, stats.ReservedStore, 0)
		require_Equal(t, stats.ReservedMemory, 0)
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamUsageReservationNegativeMaxBytes(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", replicas)
			defer c.shutdown()
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		fileCfg := &nats.StreamConfig{Name: "FILE", Storage: nats.FileStorage, Replicas: replicas, MaxBytes: 1024}
		memCfg := &nats.StreamConfig{Name: "MEM", Storage: nats.MemoryStorage, Replicas: replicas, MaxBytes: 1024}

		_, err := js.AddStream(fileCfg)
		require_NoError(t, err)
		_, err = js.AddStream(memCfg)
		require_NoError(t, err)

		acc := s.globalAccount()
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			if streams := acc.numStreams(); streams != 2 {
				return fmt.Errorf("not at 2 streams yet, got %d", streams)
			}
			return nil
		})

		validateReserved := func(total uint64) {
			t.Helper()
			checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
				stats := acc.JetStreamUsage()
				if stats.ReservedMemory != total {
					return fmt.Errorf("acc stats: expected %d, got %d", total, stats.ReservedMemory)
				}
				if stats.ReservedStore != total {
					return fmt.Errorf("acc stats: expected %d, got %d", total, stats.ReservedStore)
				}
				jstats := s.getJetStream().usageStats()
				if jstats.ReservedMemory != total {
					return fmt.Errorf("server stats: expected %d, got %d", total, jstats.ReservedMemory)
				}
				if jstats.ReservedStore != total {
					return fmt.Errorf("server stats: expected %d, got %d", total, jstats.ReservedStore)
				}
				return nil
			})
		}
		validateReserved(1024)

		// Resetting back to zero.
		fileCfg.MaxBytes, memCfg.MaxBytes = 0, 0
		_, err = js.UpdateStream(fileCfg)
		require_NoError(t, err)
		_, err = js.UpdateStream(memCfg)
		require_NoError(t, err)
		validateReserved(0)

		// Update to reset back again.
		fileCfg.MaxBytes, memCfg.MaxBytes = 512, 512
		_, err = js.UpdateStream(fileCfg)
		require_NoError(t, err)
		_, err = js.UpdateStream(memCfg)
		require_NoError(t, err)
		validateReserved(512)

		// Resetting back to -1 should mean zero as well, and should do proper accounting.
		fileCfg.MaxBytes, memCfg.MaxBytes = -1, -1
		_, err = js.UpdateStream(fileCfg)
		require_NoError(t, err)
		_, err = js.UpdateStream(memCfg)
		require_NoError(t, err)
		validateReserved(0)
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamSnapshots(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	mname := "MY-STREAM"
	subjects := []string{"foo", "bar", "baz"}
	cfg := StreamConfig{
		Name:     mname,
		Storage:  FileStorage,
		Subjects: subjects,
		MaxMsgs:  1000,
	}

	acc := s.GlobalAccount()
	mset, err := acc.addStream(&cfg)
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	// Make sure we send some as floor.
	toSend := rand.Intn(200) + 22
	for i := 1; i <= toSend; i++ {
		msg := fmt.Sprintf("Hello World %d", i)
		subj := subjects[rand.Intn(len(subjects))]
		sendStreamMsg(t, nc, subj, msg)
	}

	// Create up to 10 consumers.
	numConsumers := rand.Intn(10) + 1
	var obs []obsi
	for i := 1; i <= numConsumers; i++ {
		cname := fmt.Sprintf("WQ-%d", i)
		o, err := mset.addConsumer(workerModeConfig(cname))
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		// Now grab some messages.
		toReceive := rand.Intn(toSend/2) + 1
		for r := 0; r < toReceive; r++ {
			resp, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			if resp != nil {
				resp.Respond(nil)
			}
		}
		obs = append(obs, obsi{o.config(), toReceive})
	}
	nc.Flush()

	// Snapshot state of the stream and consumers.
	info := info{mset.config(), mset.state(), obs}

	sr, err := mset.snapshot(5*time.Second, false, true)
	if err != nil {
		t.Fatalf("Error getting snapshot: %v", err)
	}
	zr := sr.Reader
	snapshot, err := io.ReadAll(zr)
	if err != nil {
		t.Fatalf("Error reading snapshot")
	}
	// Try to restore from snapshot with current stream present, should error.
	r := bytes.NewReader(snapshot)
	if _, err := acc.RestoreStream(&info.cfg, r); err == nil {
		t.Fatalf("Expected an error trying to restore existing stream")
	} else if !strings.Contains(err.Error(), "name already in use") {
		t.Fatalf("Incorrect error received: %v", err)
	}
	// Now delete so we can restore.
	pusage := acc.JetStreamUsage()
	mset.delete()
	r.Reset(snapshot)

	mset, err = acc.RestoreStream(&info.cfg, r)
	require_NoError(t, err)
	// Now compare to make sure they are equal.
	if nusage := acc.JetStreamUsage(); !reflect.DeepEqual(nusage, pusage) {
		t.Fatalf("Usage does not match after restore: %+v vs %+v", nusage, pusage)
	}
	if state := mset.state(); !reflect.DeepEqual(state, info.state) {
		t.Fatalf("State does not match: %+v vs %+v", state, info.state)
	}
	if cfg := mset.config(); !reflect.DeepEqual(cfg, info.cfg) {
		t.Fatalf("Configs do not match: %+v vs %+v", cfg, info.cfg)
	}
	// Consumers.
	if mset.numConsumers() != len(info.obs) {
		t.Fatalf("Number of consumers do not match: %d vs %d", mset.numConsumers(), len(info.obs))
	}
	for _, oi := range info.obs {
		if o := mset.lookupConsumer(oi.cfg.Durable); o != nil {
			if uint64(oi.ack+1) != o.nextSeq() {
				t.Fatalf("[%v] Consumer next seq is not correct: %d vs %d", o.String(), oi.ack+1, o.nextSeq())
			}
		} else {
			t.Fatalf("Expected to get an consumer")
		}
	}

	// Now try restoring to a different
	s2 := RunBasicJetStreamServer(t)
	defer s2.Shutdown()

	acc = s2.GlobalAccount()
	r.Reset(snapshot)
	mset, err = acc.RestoreStream(&info.cfg, r)
	require_NoError(t, err)

	o := mset.lookupConsumer("WQ-1")
	if o == nil {
		t.Fatalf("Could not lookup consumer")
	}

	nc2 := clientConnectToServer(t, s2)
	defer nc2.Close()

	// Make sure we can read messages.
	if _, err := nc2.Request(o.requestNextMsgSubject(), nil, 5*time.Second); err != nil {
		t.Fatalf("Unexpected error getting next message: %v", err)
	}
}

func TestJetStreamSnapshotsAPI(t *testing.T) {
	lopts := DefaultTestOptions
	lopts.ServerName = "LS"
	lopts.Port = -1
	lopts.LeafNode.Host = lopts.Host
	lopts.LeafNode.Port = -1

	ls := RunServer(&lopts)
	defer ls.Shutdown()

	opts := DefaultTestOptions
	opts.ServerName = "S"
	opts.Port = -1
	tdir := t.TempDir()
	opts.JetStream = true
	opts.JetStreamDomain = "domain"
	opts.StoreDir = tdir
	maxStore := int64(1024 * 1024 * 1024)
	opts.maxStoreSet = true
	opts.JetStreamMaxStore = maxStore
	rurl, _ := url.Parse(fmt.Sprintf("nats-leaf://%s:%d", lopts.LeafNode.Host, lopts.LeafNode.Port))
	opts.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{rurl}}}

	s := RunServer(&opts)
	defer s.Shutdown()

	checkLeafNodeConnected(t, s)

	mname := "MY-STREAM"
	subjects := []string{"foo", "bar", "baz"}
	cfg := StreamConfig{
		Name:     mname,
		Storage:  FileStorage,
		Subjects: subjects,
		MaxMsgs:  1000,
	}

	acc := s.GlobalAccount()
	mset, err := acc.addStreamWithStore(&cfg, &FileStoreConfig{BlockSize: 128})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	toSend := rand.Intn(100) + 1
	for i := 1; i <= toSend; i++ {
		msg := fmt.Sprintf("Hello World %d", i)
		subj := subjects[rand.Intn(len(subjects))]
		sendStreamMsg(t, nc, subj, msg)
	}

	o, err := mset.addConsumer(workerModeConfig("WQ"))
	require_NoError(t, err)
	// Now grab some messages.
	toReceive := rand.Intn(toSend) + 1
	for r := 0; r < toReceive; r++ {
		resp, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if resp != nil {
			resp.Respond(nil)
		}
	}

	// Make sure we get proper error for non-existent request, streams,etc,
	rmsg, err := nc.Request(fmt.Sprintf(JSApiStreamSnapshotT, "foo"), nil, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	var resp JSApiStreamSnapshotResponse
	json.Unmarshal(rmsg.Data, &resp)
	if resp.Error == nil || resp.Error.Code != 400 || resp.Error.Description != "bad request" {
		t.Fatalf("Did not get correct error response: %+v", resp.Error)
	}

	sreq := &JSApiStreamSnapshotRequest{}
	req, _ := json.Marshal(sreq)
	rmsg, err = nc.Request(fmt.Sprintf(JSApiStreamSnapshotT, "foo"), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	json.Unmarshal(rmsg.Data, &resp)
	if resp.Error == nil || resp.Error.Code != 404 || resp.Error.Description != "stream not found" {
		t.Fatalf("Did not get correct error response: %+v", resp.Error)
	}

	rmsg, err = nc.Request(fmt.Sprintf(JSApiStreamSnapshotT, mname), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	json.Unmarshal(rmsg.Data, &resp)
	if resp.Error == nil || resp.Error.Code != 400 || resp.Error.Description != "deliver subject not valid" {
		t.Fatalf("Did not get correct error response: %+v", resp.Error)
	}

	// Set delivery subject, do not subscribe yet. Want this to be an ok pattern.
	sreq.DeliverSubject = nats.NewInbox()
	// Just for test, usually left alone.
	sreq.ChunkSize = 1024
	req, _ = json.Marshal(sreq)
	rmsg, err = nc.Request(fmt.Sprintf(JSApiStreamSnapshotT, mname), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	resp.Error = nil
	json.Unmarshal(rmsg.Data, &resp)
	if resp.Error != nil {
		t.Fatalf("Did not get correct error response: %+v", resp.Error)
	}
	// Check that we have the config and the state.
	if resp.Config == nil {
		t.Fatalf("Expected a stream config in the response, got %+v\n", resp)
	}
	if resp.State == nil {
		t.Fatalf("Expected a stream state in the response, got %+v\n", resp)
	}

	// Grab state for comparison.
	state := *resp.State
	config := *resp.Config

	// Setup to process snapshot chunks.
	var snapshot []byte
	done := make(chan bool)

	sub, _ := nc.Subscribe(sreq.DeliverSubject, func(m *nats.Msg) {
		// EOF
		if len(m.Data) == 0 {
			done <- true
			return
		}
		// Could be writing to a file here too.
		snapshot = append(snapshot, m.Data...)
		// Flow ack
		m.Respond(nil)
	})
	defer sub.Unsubscribe()

	// Wait to receive the snapshot.
	select {
	case <-done:
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive our snapshot in time")
	}

	// Now make sure this snapshot is legit.
	var rresp JSApiStreamRestoreResponse
	rreq := &JSApiStreamRestoreRequest{
		Config: config,
		State:  state,
	}
	req, _ = json.Marshal(rreq)

	// Make sure we get an error since stream still exists.
	rmsg, err = nc.Request(fmt.Sprintf(JSApiStreamRestoreT, mname), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	json.Unmarshal(rmsg.Data, &rresp)
	if !IsNatsErr(rresp.Error, JSStreamNameExistRestoreFailedErr) {
		t.Fatalf("Did not get correct error response: %+v", rresp.Error)
	}

	// Delete this stream.
	mset.delete()

	// Sending no request message will error now.
	rmsg, err = nc.Request(fmt.Sprintf(JSApiStreamRestoreT, mname), nil, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	// Make sure to clear.
	rresp.Error = nil
	json.Unmarshal(rmsg.Data, &rresp)
	if rresp.Error == nil || rresp.Error.Code != 400 || rresp.Error.Description != "bad request" {
		t.Fatalf("Did not get correct error response: %+v", rresp.Error)
	}

	// This should work.
	rmsg, err = nc.Request(fmt.Sprintf(JSApiStreamRestoreT, mname), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	// Make sure to clear.
	rresp.Error = nil
	json.Unmarshal(rmsg.Data, &rresp)
	if rresp.Error != nil {
		t.Fatalf("Got an unexpected error response: %+v", rresp.Error)
	}

	// Can be any size message.
	var chunk [512]byte
	for r := bytes.NewReader(snapshot); ; {
		n, err := r.Read(chunk[:])
		if err != nil {
			break
		}
		nc.Request(rresp.DeliverSubject, chunk[:n], time.Second)
	}
	nc.Request(rresp.DeliverSubject, nil, time.Second)

	mset, err = acc.lookupStream(mname)
	if err != nil {
		t.Fatalf("Expected to find a stream for %q", mname)
	}
	if !reflect.DeepEqual(mset.state(), state) {
		t.Fatalf("Did not match states, %+v vs %+v", mset.state(), state)
	}

	// Now ask that the stream be checked first.
	sreq.ChunkSize = 0
	sreq.CheckMsgs = true
	snapshot = snapshot[:0]

	req, _ = json.Marshal(sreq)
	if _, err = nc.Request(fmt.Sprintf(JSApiStreamSnapshotT, mname), req, 5*time.Second); err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	// Wait to receive the snapshot.
	select {
	case <-done:
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive our snapshot in time")
	}

	// Now connect through a cluster server and make sure we can get things to work this way as well.
	// This client, connecting to a leaf without shared system account and domain needs to provide the domain explicitly.
	nc2 := clientConnectToServer(t, ls)
	defer nc2.Close()
	// Wait a bit for interest to propagate.
	time.Sleep(100 * time.Millisecond)

	snapshot = snapshot[:0]

	req, _ = json.Marshal(sreq)
	rmsg, err = nc2.Request(fmt.Sprintf(strings.ReplaceAll(JSApiStreamSnapshotT, JSApiPrefix, "$JS.domain.API"), mname), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	resp.Error = nil
	json.Unmarshal(rmsg.Data, &resp)
	if resp.Error != nil {
		t.Fatalf("Did not get correct error response: %+v", resp.Error)
	}
	// Wait to receive the snapshot.
	select {
	case <-done:
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive our snapshot in time")
	}

	// Now do a restore through the new client connection.
	// Delete this stream first.
	mset, err = acc.lookupStream(mname)
	if err != nil {
		t.Fatalf("Expected to find a stream for %q", mname)
	}
	state = mset.state()
	mset.delete()

	req, _ = json.Marshal(rreq)
	rmsg, err = nc2.Request(fmt.Sprintf(strings.ReplaceAll(JSApiStreamRestoreT, JSApiPrefix, "$JS.domain.API"), mname), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	// Make sure to clear.
	rresp.Error = nil
	json.Unmarshal(rmsg.Data, &rresp)
	if rresp.Error != nil {
		t.Fatalf("Got an unexpected error response: %+v", rresp.Error)
	}

	// Make sure when we send something without a reply subject the subscription is shutoff.
	r := bytes.NewReader(snapshot)
	n, _ := r.Read(chunk[:])
	nc2.Publish(rresp.DeliverSubject, chunk[:n])
	nc2.Flush()
	n, _ = r.Read(chunk[:])
	if _, err := nc2.Request(rresp.DeliverSubject, chunk[:n], 100*time.Millisecond); err == nil {
		t.Fatalf("Expected restore subscription to be closed")
	}

	req, _ = json.Marshal(rreq)
	rmsg, err = nc2.Request(fmt.Sprintf(strings.ReplaceAll(JSApiStreamRestoreT, JSApiPrefix, "$JS.domain.API"), mname), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	// Make sure to clear.
	rresp.Error = nil
	json.Unmarshal(rmsg.Data, &rresp)
	if rresp.Error != nil {
		t.Fatalf("Got an unexpected error response: %+v", rresp.Error)
	}

	for r := bytes.NewReader(snapshot); ; {
		n, err := r.Read(chunk[:])
		if err != nil {
			break
		}
		// Make sure other side responds to reply subjects for ack flow. Optional.
		if _, err := nc2.Request(rresp.DeliverSubject, chunk[:n], time.Second); err != nil {
			t.Fatalf("Restore not honoring reply subjects for ack flow")
		}
	}

	// For EOF this will send back stream info or an error.
	si, err := nc2.Request(rresp.DeliverSubject, nil, time.Second)
	if err != nil {
		t.Fatalf("Got an error restoring stream: %v", err)
	}
	var scResp JSApiStreamCreateResponse
	if err := json.Unmarshal(si.Data, &scResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if scResp.Error != nil {
		t.Fatalf("Got an unexpected error from EOF on restore: %+v", scResp.Error)
	}

	if !reflect.DeepEqual(scResp.StreamInfo.State, state) {
		t.Fatalf("Did not match states, %+v vs %+v", scResp.StreamInfo.State, state)
	}

	// Now make sure that if we try to change the name/identity of the stream we get an error.
	mset, err = acc.lookupStream(mname)
	if err != nil {
		t.Fatalf("Expected to find a stream for %q", mname)
	}
	mset.state()
	mset.delete()

	rreq.Config.Name = "NEW_STREAM"
	req, _ = json.Marshal(rreq)

	rmsg, err = nc2.Request(fmt.Sprintf(strings.ReplaceAll(JSApiStreamRestoreT, JSApiPrefix, "$JS.domain.API"), rreq.Config.Name), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}
	// Make sure to clear.
	rresp.Error = nil
	json.Unmarshal(rmsg.Data, &rresp)
	// We should not get an error here.
	if rresp.Error != nil {
		t.Fatalf("Got an unexpected error response: %+v", rresp.Error)
	}
	for r := bytes.NewReader(snapshot); ; {
		n, err := r.Read(chunk[:])
		if err != nil {
			break
		}
		nc2.Request(rresp.DeliverSubject, chunk[:n], time.Second)
	}

	si, err = nc2.Request(rresp.DeliverSubject, nil, time.Second)
	require_NoError(t, err)

	scResp.Error = nil
	if err := json.Unmarshal(si.Data, &scResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if scResp.Error == nil {
		t.Fatalf("Expected an error but got none")
	}
	expect := "names do not match"
	if !strings.Contains(scResp.Error.Description, expect) {
		t.Fatalf("Expected description of %q, got %q", expect, scResp.Error.Description)
	}
}

func TestJetStreamPubAckPerf(t *testing.T) {
	// Comment out to run, holding place for now.
	t.SkipNow()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "foo", Storage: nats.MemoryStorage}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	toSend := 1_000_000
	start := time.Now()
	for i := 0; i < toSend; i++ {
		js.PublishAsync("foo", []byte("OK"))
	}
	<-js.PublishAsyncComplete()
	tt := time.Since(start)
	fmt.Printf("time is %v\n", tt)
	fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds())
}

func TestJetStreamPubPerfWithFullStream(t *testing.T) {
	// Comment out to run, holding place for now.
	t.SkipNow()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	toSend, msg := 1_000_000, []byte("OK")

	_, err := js.AddStream(&nats.StreamConfig{Name: "foo", MaxMsgs: int64(toSend)})
	require_NoError(t, err)

	start := time.Now()
	for i := 0; i < toSend; i++ {
		js.PublishAsync("foo", msg)
	}
	<-js.PublishAsyncComplete()
	tt := time.Since(start)
	fmt.Printf("time is %v\n", tt)
	fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds())

	// Now do same amount but knowing we are at our limit.
	start = time.Now()
	for i := 0; i < toSend; i++ {
		js.PublishAsync("foo", msg)
	}
	<-js.PublishAsyncComplete()
	tt = time.Since(start)
	fmt.Printf("\ntime is %v\n", tt)
	fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds())
}

func TestJetStreamSnapshotsAPIPerf(t *testing.T) {
	// Comment out to run, holding place for now.
	t.SkipNow()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	cfg := StreamConfig{
		Name:    "snap-perf",
		Storage: FileStorage,
	}

	acc := s.GlobalAccount()
	if _, err := acc.addStream(&cfg); err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	msg := make([]byte, 128*1024)
	// If you don't give gzip some data will spend too much time compressing everything to zero.
	crand.Read(msg)

	for i := 0; i < 10000; i++ {
		nc.Publish("snap-perf", msg)
	}
	nc.Flush()

	sreq := &JSApiStreamSnapshotRequest{DeliverSubject: nats.NewInbox()}
	req, _ := json.Marshal(sreq)
	rmsg, err := nc.Request(fmt.Sprintf(JSApiStreamSnapshotT, "snap-perf"), req, time.Second)
	if err != nil {
		t.Fatalf("Unexpected error on snapshot request: %v", err)
	}

	var resp JSApiStreamSnapshotResponse
	json.Unmarshal(rmsg.Data, &resp)
	if resp.Error != nil {
		t.Fatalf("Did not get correct error response: %+v", resp.Error)
	}

	done := make(chan bool)
	total := 0
	sub, _ := nc.Subscribe(sreq.DeliverSubject, func(m *nats.Msg) {
		// EOF
		if len(m.Data) == 0 {
			m.Sub.Unsubscribe()
			done <- true
			return
		}
		// We don't do anything with the snapshot, just take
		// note of the size.
		total += len(m.Data)
		// Flow ack
		m.Respond(nil)
	})
	defer sub.Unsubscribe()

	start := time.Now()
	// Wait to receive the snapshot.
	select {
	case <-done:
	case <-time.After(30 * time.Second):
		t.Fatalf("Did not receive our snapshot in time")
	}
	td := time.Since(start)
	fmt.Printf("Received %d bytes in %v\n", total, td)
	fmt.Printf("Rate %.0f MB/s\n", float64(total)/td.Seconds()/(1024*1024))
}

func TestJetStreamActiveDelivery(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "ADS", Storage: MemoryStorage, Subjects: []string{"foo.*"}}},
		{"FileStore", &StreamConfig{Name: "ADS", Storage: FileStorage, Subjects: []string{"foo.*"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Now load up some messages.
			toSend := 100
			sendSubj := "foo.22"
			for i := 0; i < toSend; i++ {
				sendStreamMsg(t, nc, sendSubj, "Hello World!")
			}
			state := mset.state()
			if state.Msgs != uint64(toSend) {
				t.Fatalf("Expected %d messages, got %d", toSend, state.Msgs)
			}

			o, err := mset.addConsumer(&ConsumerConfig{Durable: "to", DeliverSubject: "d"})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			// We have no active interest above. So consumer will be considered inactive. Let's subscribe and make sure
			// we get the messages instantly. This will test that we hook interest activation correctly.
			sub, _ := nc.SubscribeSync("d")
			defer sub.Unsubscribe()
			nc.Flush()

			checkFor(t, 100*time.Millisecond, 10*time.Millisecond, func() error {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != toSend {
					return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, toSend)
				}
				return nil
			})
		})
	}
}

func TestJetStreamEphemeralConsumers(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "EP", Storage: MemoryStorage, Subjects: []string{"foo.*"}}},
		{"FileStore", &StreamConfig{Name: "EP", Storage: FileStorage, Subjects: []string{"foo.*"}}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			sub, _ := nc.SubscribeSync(nats.NewInbox())
			defer sub.Unsubscribe()
			nc.Flush()

			o, err := mset.addConsumer(&ConsumerConfig{DeliverSubject: sub.Subject})
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			if !o.isActive() {
				t.Fatalf("Expected the consumer to be considered active")
			}
			if numo := mset.numConsumers(); numo != 1 {
				t.Fatalf("Expected number of consumers to be 1, got %d", numo)
			}
			// Set our delete threshold to something low for testing purposes.
			o.setInActiveDeleteThreshold(100 * time.Millisecond)

			// Make sure works now.
			nc.Request("foo.22", nil, 100*time.Millisecond)
			checkFor(t, 250*time.Millisecond, 10*time.Millisecond, func() error {
				if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != 1 {
					return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, 1)
				}
				return nil
			})

			// Now close the subscription, this should trip active state on the ephemeral consumer.
			sub.Unsubscribe()
			checkFor(t, time.Second, 10*time.Millisecond, func() error {
				if o.isActive() {
					return fmt.Errorf("Expected the ephemeral consumer to be considered inactive")
				}
				return nil
			})
			// The reason for this still being 1 is that we give some time in case of a reconnect scenario.
			// We detect right away on the interest change but we wait for interest to be re-established.
			// This is in case server goes away but app is fine, we do not want to recycle those consumers.
			if numo := mset.numConsumers(); numo != 1 {
				t.Fatalf("Expected number of consumers to be 1, got %d", numo)
			}

			// We should delete this one after the delete threshold.
			checkFor(t, time.Second, 100*time.Millisecond, func() error {
				if numo := mset.numConsumers(); numo != 0 {
					return fmt.Errorf("Expected number of consumers to be 0, got %d", numo)
				}
				return nil
			})
		})
	}
}

func TestJetStreamMetadata(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "DC", Retention: WorkQueuePolicy, Storage: MemoryStorage}},
		{"FileStore", &StreamConfig{Name: "DC", Retention: WorkQueuePolicy, Storage: FileStorage}},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			for i := 0; i < 10; i++ {
				nc.Publish("DC", []byte("OK!"))
				nc.Flush()
				time.Sleep(time.Millisecond)
			}

			if state := mset.state(); state.Msgs != 10 {
				t.Fatalf("Expected %d messages, got %d", 10, state.Msgs)
			}

			o, err := mset.addConsumer(workerModeConfig("WQ"))
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			for i := uint64(1); i <= 10; i++ {
				m, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}

				sseq, dseq, dcount, ts, _ := replyInfo(m.Reply)

				mreq := &JSApiMsgGetRequest{Seq: sseq}
				req, err := json.Marshal(mreq)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				// Load the original message from the stream to verify ReplyInfo ts against stored message
				smsgj, err := nc.Request(fmt.Sprintf(JSApiMsgGetT, c.mconfig.Name), req, time.Second)
				if err != nil {
					t.Fatalf("Could not retrieve stream message: %v", err)
				}

				var resp JSApiMsgGetResponse
				err = json.Unmarshal(smsgj.Data, &resp)
				if err != nil {
					t.Fatalf("Could not parse stream message: %v", err)
				}
				if resp.Message == nil || resp.Error != nil {
					t.Fatalf("Did not receive correct response")
				}
				smsg := resp.Message
				if ts != smsg.Time.UnixNano() {
					t.Fatalf("Wrong timestamp in ReplyInfo for msg %d, expected %v got %v", i, ts, smsg.Time.UnixNano())
				}
				if sseq != i {
					t.Fatalf("Expected set sequence of %d, got %d", i, sseq)
				}
				if dseq != i {
					t.Fatalf("Expected delivery sequence of %d, got %d", i, dseq)
				}
				if dcount != 1 {
					t.Fatalf("Expected delivery count to be 1, got %d", dcount)
				}
				m.Respond(AckAck)
			}

			// Now make sure we get right response when message is missing.
			mreq := &JSApiMsgGetRequest{Seq: 1}
			req, err := json.Marshal(mreq)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			// Load the original message from the stream to verify ReplyInfo ts against stored message
			rmsg, err := nc.Request(fmt.Sprintf(JSApiMsgGetT, c.mconfig.Name), req, time.Second)
			if err != nil {
				t.Fatalf("Could not retrieve stream message: %v", err)
			}
			var resp JSApiMsgGetResponse
			err = json.Unmarshal(rmsg.Data, &resp)
			if err != nil {
				t.Fatalf("Could not parse stream message: %v", err)
			}
			if resp.Error == nil || resp.Error.Code != 404 || resp.Error.Description != "no message found" {
				t.Fatalf("Did not get correct error response: %+v", resp.Error)
			}
		})
	}
}
func TestJetStreamRedeliverCount(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "DC", Storage: MemoryStorage}},
		{"FileStore", &StreamConfig{Name: "DC", Storage: FileStorage}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			if _, err = js.Publish("DC", []byte("OK!")); err != nil {
				t.Fatal(err)
			}
			checkFor(t, time.Second, time.Millisecond*250, func() error {
				if state := mset.state(); state.Msgs != 1 {
					return fmt.Errorf("Expected %d messages, got %d", 1, state.Msgs)
				}
				return nil
			})

			o, err := mset.addConsumer(workerModeConfig("WQ"))
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			for i := uint64(1); i <= 10; i++ {
				m, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}

				sseq, dseq, dcount, _, _ := replyInfo(m.Reply)

				// Make sure we keep getting stream sequence #1
				if sseq != 1 {
					t.Fatalf("Expected set sequence of 1, got %d", sseq)
				}
				if dseq != i {
					t.Fatalf("Expected delivery sequence of %d, got %d", i, dseq)
				}
				// Now make sure dcount is same as dseq (or i).
				if dcount != i {
					t.Fatalf("Expected delivery count to be %d, got %d", i, dcount)
				}

				// Make sure it keeps getting sent back.
				m.Respond(AckNak)
				nc.Flush()
			}
		})
	}
}

// We want to make sure that for pull based consumers that if we ack
// late with no interest the redelivery attempt is removed and we do
// not get the message back.
func TestJetStreamRedeliverAndLateAck(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: "LA", Storage: MemoryStorage})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	o, err := mset.addConsumer(&ConsumerConfig{Durable: "DDD", AckPolicy: AckExplicit, AckWait: 100 * time.Millisecond})
	if err != nil {
		t.Fatalf("Expected no error with registered interest, got %v", err)
	}
	defer o.delete()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	// Queue up message
	sendStreamMsg(t, nc, "LA", "Hello World!")

	nextSubj := o.requestNextMsgSubject()
	msg, err := nc.Request(nextSubj, nil, time.Second)
	require_NoError(t, err)

	// Wait for past ackwait time
	time.Sleep(150 * time.Millisecond)
	// Now ack!
	msg.AckSync()
	// We should not get this back.
	if _, err := nc.Request(nextSubj, nil, 10*time.Millisecond); err == nil {
		t.Fatalf("Message should not have been sent back")
	}
}

// https://github.com/nats-io/nats-server/issues/1502
func TestJetStreamPendingNextTimer(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: "NT", Storage: MemoryStorage, Subjects: []string{"ORDERS.*"}})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	o, err := mset.addConsumer(&ConsumerConfig{
		Durable:       "DDD",
		AckPolicy:     AckExplicit,
		FilterSubject: "ORDERS.test",
		AckWait:       100 * time.Millisecond,
	})
	if err != nil {
		t.Fatalf("Expected no error with registered interest, got %v", err)
	}
	defer o.delete()

	sendAndReceive := func() {
		nc := clientConnectToServer(t, s)
		defer nc.Close()

		// Queue up message
		sendStreamMsg(t, nc, "ORDERS.test", "Hello World! #1")
		sendStreamMsg(t, nc, "ORDERS.test", "Hello World! #2")

		nextSubj := o.requestNextMsgSubject()
		for i := 0; i < 2; i++ {
			if _, err := nc.Request(nextSubj, nil, time.Second); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
		}
		nc.Close()
		time.Sleep(200 * time.Millisecond)
	}

	sendAndReceive()
	sendAndReceive()
	sendAndReceive()
}

func TestJetStreamCanNotNakAckd(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "DC", Storage: MemoryStorage}},
		{"FileStore", &StreamConfig{Name: "DC", Storage: FileStorage}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			// Send 10 msgs
			for i := 0; i < 10; i++ {
				js.Publish("DC", []byte("OK!"))
			}
			if state := mset.state(); state.Msgs != 10 {
				t.Fatalf("Expected %d messages, got %d", 10, state.Msgs)
			}

			o, err := mset.addConsumer(workerModeConfig("WQ"))
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			for i := uint64(1); i <= 10; i++ {
				m, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				// Ack evens.
				if i%2 == 0 {
					m.Respond(nil)
				}
			}
			nc.Flush()

			// Fake these for now.
			ackReplyT := "$JS.A.DC.WQ.1.%d.%d"
			checkBadNak := func(seq int) {
				t.Helper()
				if err := nc.Publish(fmt.Sprintf(ackReplyT, seq, seq), AckNak); err != nil {
					t.Fatalf("Error sending nak: %v", err)
				}
				nc.Flush()
				if _, err := nc.Request(o.requestNextMsgSubject(), nil, 10*time.Millisecond); err != nats.ErrTimeout {
					t.Fatalf("Did not expect new delivery on nak of %d", seq)
				}
			}

			// If the nak took action it will deliver another message, incrementing the next delivery seq.
			// We ack evens above, so these should fail
			for i := 2; i <= 10; i += 2 {
				checkBadNak(i)
			}

			// Now check we can not nak something we do not have.
			checkBadNak(22)
		})
	}
}

func TestJetStreamStreamPurge(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "DC", Storage: MemoryStorage}},
		{"FileStore", &StreamConfig{Name: "DC", Storage: FileStorage}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			// Send 100 msgs
			for i := 0; i < 100; i++ {
				js.Publish("DC", []byte("OK!"))
			}
			if state := mset.state(); state.Msgs != 100 {
				t.Fatalf("Expected %d messages, got %d", 100, state.Msgs)
			}
			mset.purge(nil)
			state := mset.state()
			if state.Msgs != 0 {
				t.Fatalf("Expected %d messages, got %d", 0, state.Msgs)
			}
			// Make sure first timestamp are reset.
			if !state.FirstTime.IsZero() {
				t.Fatalf("Expected the state's first time to be zero after purge")
			}
			time.Sleep(10 * time.Millisecond)
			now := time.Now()
			js.Publish("DC", []byte("OK!"))

			state = mset.state()
			if state.Msgs != 1 {
				t.Fatalf("Expected %d message, got %d", 1, state.Msgs)
			}
			if state.FirstTime.Before(now) {
				t.Fatalf("First time is incorrect after adding messages back in")
			}
			if state.FirstTime != state.LastTime {
				t.Fatalf("Expected first and last times to be the same for only message")
			}
		})
	}
}

func TestJetStreamStreamPurgeWithConsumer(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "DC", Storage: MemoryStorage}},
		{"FileStore", &StreamConfig{Name: "DC", Storage: FileStorage}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			// Send 100 msgs
			for i := 0; i < 100; i++ {
				js.Publish("DC", []byte("OK!"))
			}
			if state := mset.state(); state.Msgs != 100 {
				t.Fatalf("Expected %d messages, got %d", 100, state.Msgs)
			}
			// Now create an consumer and make sure it functions properly.
			o, err := mset.addConsumer(workerModeConfig("WQ"))
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()
			nextSubj := o.requestNextMsgSubject()
			for i := 0; i < 50; i++ {
				msg, err := nc.Request(nextSubj, nil, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				// Ack.
				msg.Respond(nil)
			}
			// Now grab next 25 without ack.
			for i := 0; i < 25; i++ {
				if _, err := nc.Request(nextSubj, nil, time.Second); err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
			}
			state := o.info()
			if state.AckFloor.Consumer != 50 {
				t.Fatalf("Expected ack floor of 50, got %d", state.AckFloor.Consumer)
			}
			if state.NumAckPending != 25 {
				t.Fatalf("Expected len(pending) to be 25, got %d", state.NumAckPending)
			}
			// Now do purge.
			mset.purge(nil)
			if state := mset.state(); state.Msgs != 0 {
				t.Fatalf("Expected %d messages, got %d", 0, state.Msgs)
			}
			// Now re-acquire state and check that we did the right thing.
			// Pending should be cleared, and stream sequences should have been set
			// to the total messages before purge + 1.
			state = o.info()
			if state.NumAckPending != 0 {
				t.Fatalf("Expected no pending, got %d", state.NumAckPending)
			}
			if state.Delivered.Stream != 100 {
				t.Fatalf("Expected to have setseq now at next seq of 100, got %d", state.Delivered.Stream)
			}
			// Check AckFloors which should have also been adjusted.
			if state.AckFloor.Stream != 100 {
				t.Fatalf("Expected ackfloor for setseq to be 100, got %d", state.AckFloor.Stream)
			}
			if state.AckFloor.Consumer != 75 {
				t.Fatalf("Expected ackfloor for obsseq to be 75, got %d", state.AckFloor.Consumer)
			}
			// Also make sure we can get new messages correctly.
			js.Publish("DC", []byte("OK-22"))
			if msg, err := nc.Request(nextSubj, nil, time.Second); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			} else if string(msg.Data) != "OK-22" {
				t.Fatalf("Received wrong message, wanted 'OK-22', got %q", msg.Data)
			}
		})
	}
}

func TestJetStreamStreamPurgeWithConsumerAndRedelivery(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "DC", Storage: MemoryStorage}},
		{"FileStore", &StreamConfig{Name: "DC", Storage: FileStorage}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			// Send 100 msgs
			for i := 0; i < 100; i++ {
				js.Publish("DC", []byte("OK!"))
			}
			if state := mset.state(); state.Msgs != 100 {
				t.Fatalf("Expected %d messages, got %d", 100, state.Msgs)
			}
			// Now create an consumer and make sure it functions properly.
			// This will test redelivery state and purge of the stream.
			wcfg := &ConsumerConfig{
				Durable:   "WQ",
				AckPolicy: AckExplicit,
				AckWait:   20 * time.Millisecond,
			}
			o, err := mset.addConsumer(wcfg)
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()
			nextSubj := o.requestNextMsgSubject()
			for i := 0; i < 50; i++ {
				// Do not ack these.
				if _, err := nc.Request(nextSubj, nil, time.Second); err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
			}
			// Now wait to make sure we are in a redelivered state.
			time.Sleep(wcfg.AckWait * 2)
			// Now do purge.
			mset.purge(nil)
			if state := mset.state(); state.Msgs != 0 {
				t.Fatalf("Expected %d messages, got %d", 0, state.Msgs)
			}
			// Now get the state and check that we did the right thing.
			// Pending should be cleared, and stream sequences should have been set
			// to the total messages before purge + 1.
			state := o.info()
			if state.NumAckPending != 0 {
				t.Fatalf("Expected no pending, got %d", state.NumAckPending)
			}
			if state.Delivered.Stream != 100 {
				t.Fatalf("Expected to have setseq now at next seq of 100, got %d", state.Delivered.Stream)
			}
			// Check AckFloors which should have also been adjusted.
			if state.AckFloor.Stream != 100 {
				t.Fatalf("Expected ackfloor for setseq to be 100, got %d", state.AckFloor.Stream)
			}
			if state.AckFloor.Consumer != 50 {
				t.Fatalf("Expected ackfloor for obsseq to be 75, got %d", state.AckFloor.Consumer)
			}
			// Also make sure we can get new messages correctly.
			js.Publish("DC", []byte("OK-22"))
			if msg, err := nc.Request(nextSubj, nil, time.Second); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			} else if string(msg.Data) != "OK-22" {
				t.Fatalf("Received wrong message, wanted 'OK-22', got %q", msg.Data)
			}
		})
	}
}

func TestJetStreamInterestRetentionStream(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "DC", Storage: MemoryStorage, Retention: InterestPolicy}},
		{"FileStore", &StreamConfig{Name: "DC", Storage: FileStorage, Retention: InterestPolicy}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			// Send 100 msgs
			totalMsgs := 100

			for i := 0; i < totalMsgs; i++ {
				js.Publish("DC", []byte("OK!"))
			}

			checkNumMsgs := func(numExpected int) {
				t.Helper()
				checkFor(t, time.Second, 15*time.Millisecond, func() error {
					if state := mset.state(); state.Msgs != uint64(numExpected) {
						return fmt.Errorf("Expected %d messages, got %d", numExpected, state.Msgs)
					}
					return nil
				})
			}

			// Since we had no interest this should be 0.
			checkNumMsgs(0)

			syncSub := func() *nats.Subscription {
				sub, _ := nc.SubscribeSync(nats.NewInbox())
				nc.Flush()
				return sub
			}

			// Now create three consumers.
			// 1. AckExplicit
			// 2. AckAll
			// 3. AckNone

			sub1 := syncSub()
			mset.addConsumer(&ConsumerConfig{DeliverSubject: sub1.Subject, AckPolicy: AckExplicit})

			sub2 := syncSub()
			mset.addConsumer(&ConsumerConfig{DeliverSubject: sub2.Subject, AckPolicy: AckAll})

			sub3 := syncSub()
			mset.addConsumer(&ConsumerConfig{DeliverSubject: sub3.Subject, AckPolicy: AckNone})

			for i := 0; i < totalMsgs; i++ {
				js.Publish("DC", []byte("OK!"))
			}

			checkNumMsgs(totalMsgs)

			// Wait for all messsages to be pending for each sub.
			for i, sub := range []*nats.Subscription{sub1, sub2, sub3} {
				checkFor(t, 5*time.Second, 25*time.Millisecond, func() error {
					if nmsgs, _, _ := sub.Pending(); nmsgs != totalMsgs {
						return fmt.Errorf("Did not receive correct number of messages: %d vs %d for sub %d", nmsgs, totalMsgs, i+1)
					}
					return nil
				})
			}

			getAndAck := func(sub *nats.Subscription) {
				t.Helper()
				if m, err := sub.NextMsg(time.Second); err != nil {
					t.Fatalf("Unexpected error: %v", err)
				} else {
					m.Respond(nil)
				}
				nc.Flush()
			}

			// Ack evens for the explicit ack sub.
			var odds []*nats.Msg
			for i := 1; i <= totalMsgs; i++ {
				if m, err := sub1.NextMsg(time.Second); err != nil {
					t.Fatalf("Unexpected error: %v", err)
				} else if i%2 == 0 {
					m.Respond(nil) // Ack evens.
				} else {
					odds = append(odds, m)
				}
			}
			nc.Flush()

			checkNumMsgs(totalMsgs)

			// Now ack first for AckAll sub2
			getAndAck(sub2)
			// We should be at the same number since we acked 1, explicit acked 2
			checkNumMsgs(totalMsgs)
			// Now ack second for AckAll sub2
			getAndAck(sub2)
			// We should now have 1 removed.
			checkNumMsgs(totalMsgs - 1)
			// Now ack third for AckAll sub2
			getAndAck(sub2)
			// We should still only have 1 removed.
			checkNumMsgs(totalMsgs - 1)

			// Now ack odds from explicit.
			for _, m := range odds {
				m.Respond(nil) // Ack
			}
			nc.Flush()

			// we should have 1, 2, 3 acks now.
			checkNumMsgs(totalMsgs - 3)

			nm, _, _ := sub2.Pending()
			// Now ack last ackAll message. This should clear all of them.
			for i := 1; i <= nm; i++ {
				if m, err := sub2.NextMsg(time.Second); err != nil {
					t.Fatalf("Unexpected error: %v", err)
				} else if i == nm {
					m.Respond(nil)
				}
			}
			nc.Flush()

			// Should be zero now.
			checkNumMsgs(0)
		})
	}
}

func TestJetStreamInterestRetentionStreamWithFilteredConsumers(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "DC", Subjects: []string{"*"}, Storage: MemoryStorage, Retention: InterestPolicy}},
		{"FileStore", &StreamConfig{Name: "DC", Subjects: []string{"*"}, Storage: FileStorage, Retention: InterestPolicy}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			fsub, err := js.SubscribeSync("foo")
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			defer fsub.Unsubscribe()

			bsub, err := js.SubscribeSync("bar")
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			defer bsub.Unsubscribe()

			msg := []byte("FILTERED")
			sendMsg := func(subj string) {
				t.Helper()
				if _, err = js.Publish(subj, msg); err != nil {
					t.Fatalf("Unexpected publish error: %v", err)
				}
			}

			getAndAck := func(sub *nats.Subscription) {
				t.Helper()
				m, err := sub.NextMsg(time.Second)
				if err != nil {
					t.Fatalf("Unexpected error getting msg: %v", err)
				}
				m.AckSync()
			}

			checkState := func(expected uint64) {
				t.Helper()
				si, err := js.StreamInfo("DC")
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				if si.State.Msgs != expected {
					t.Fatalf("Expected %d msgs, got %d", expected, si.State.Msgs)
				}
			}

			sendMsg("foo")
			checkState(1)
			getAndAck(fsub)
			checkState(0)
			sendMsg("bar")
			sendMsg("foo")
			checkState(2)
			getAndAck(bsub)
			checkState(1)
			getAndAck(fsub)
			checkState(0)
		})
	}
}

func TestJetStreamInterestRetentionWithWildcardsAndFilteredConsumers(t *testing.T) {
	msc := StreamConfig{
		Name:      "DCWC",
		Subjects:  []string{"foo.*"},
		Storage:   MemoryStorage,
		Retention: InterestPolicy,
	}
	fsc := msc
	fsc.Storage = FileStorage

	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &msc},
		{"FileStore", &fsc},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			// Send 10 msgs
			for i := 0; i < 10; i++ {
				sendStreamMsg(t, nc, "foo.bar", "Hello World!")
			}
			if state := mset.state(); state.Msgs != 0 {
				t.Fatalf("Expected %d messages, got %d", 0, state.Msgs)
			}

			cfg := &ConsumerConfig{Durable: "ddd", FilterSubject: "foo.bar", AckPolicy: AckExplicit}
			o, err := mset.addConsumer(cfg)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			defer o.delete()

			sendStreamMsg(t, nc, "foo.bar", "Hello World!")
			if state := mset.state(); state.Msgs != 1 {
				t.Fatalf("Expected %d message, got %d", 1, state.Msgs)
			} else if state.FirstSeq != 11 {
				t.Fatalf("Expected %d for first seq, got %d", 11, state.FirstSeq)
			}
			// Now send to foo.baz, which has no interest, so we should not hold onto this message.
			sendStreamMsg(t, nc, "foo.baz", "Hello World!")
			if state := mset.state(); state.Msgs != 1 {
				t.Fatalf("Expected %d message, got %d", 1, state.Msgs)
			}
		})
	}
}

func TestJetStreamInterestRetentionStreamWithDurableRestart(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &StreamConfig{Name: "IK", Storage: MemoryStorage, Retention: InterestPolicy}},
		{"FileStore", &StreamConfig{Name: "IK", Storage: FileStorage, Retention: InterestPolicy}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			checkNumMsgs := func(numExpected int) {
				t.Helper()
				checkFor(t, time.Second, 50*time.Millisecond, func() error {
					if state := mset.state(); state.Msgs != uint64(numExpected) {
						return fmt.Errorf("Expected %d messages, got %d", numExpected, state.Msgs)
					}
					return nil
				})
			}

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			sub, _ := nc.SubscribeSync(nats.NewInbox())
			nc.Flush()

			cfg := &ConsumerConfig{Durable: "ivan", DeliverPolicy: DeliverNew, DeliverSubject: sub.Subject, AckPolicy: AckNone}

			o, _ := mset.addConsumer(cfg)

			sendStreamMsg(t, nc, "IK", "M1")
			sendStreamMsg(t, nc, "IK", "M2")

			checkSubPending := func(numExpected int) {
				t.Helper()
				checkFor(t, 200*time.Millisecond, 10*time.Millisecond, func() error {
					if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != numExpected {
						return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, numExpected)
					}
					return nil
				})
			}

			checkSubPending(2)
			checkNumMsgs(0)

			// Now stop the subscription.
			sub.Unsubscribe()
			checkFor(t, 200*time.Millisecond, 10*time.Millisecond, func() error {
				if o.isActive() {
					return fmt.Errorf("Still active consumer")
				}
				return nil
			})

			sendStreamMsg(t, nc, "IK", "M3")
			sendStreamMsg(t, nc, "IK", "M4")

			checkNumMsgs(2)

			// Now restart the durable.
			sub, _ = nc.SubscribeSync(nats.NewInbox())
			nc.Flush()
			cfg.DeliverSubject = sub.Subject
			if o, err = mset.addConsumer(cfg); err != nil {
				t.Fatalf("Error re-establishing the durable consumer: %v", err)
			}
			checkSubPending(2)

			for _, expected := range []string{"M3", "M4"} {
				if m, err := sub.NextMsg(time.Second); err != nil {
					t.Fatalf("Unexpected error: %v", err)
				} else if string(m.Data) != expected {
					t.Fatalf("Expected %q, got %q", expected, m.Data)
				}
			}

			// Should all be gone now.
			checkNumMsgs(0)

			// Now restart again and make sure we do not get any messages.
			sub.Unsubscribe()
			checkFor(t, 200*time.Millisecond, 10*time.Millisecond, func() error {
				if o.isActive() {
					return fmt.Errorf("Still active consumer")
				}
				return nil
			})
			o.delete()

			sub, _ = nc.SubscribeSync(nats.NewInbox())
			nc.Flush()

			cfg.DeliverSubject = sub.Subject
			cfg.AckPolicy = AckExplicit // Set ack
			if o, err = mset.addConsumer(cfg); err != nil {
				t.Fatalf("Error re-establishing the durable consumer: %v", err)
			}
			time.Sleep(100 * time.Millisecond)
			checkSubPending(0)
			checkNumMsgs(0)

			// Now queue up some messages.
			for i := 1; i <= 10; i++ {
				sendStreamMsg(t, nc, "IK", fmt.Sprintf("M%d", i))
			}
			checkNumMsgs(10)
			checkSubPending(10)

			// Create second consumer
			sub2, _ := nc.SubscribeSync(nats.NewInbox())
			nc.Flush()
			cfg.DeliverSubject = sub2.Subject
			cfg.Durable = "derek"
			o2, err := mset.addConsumer(cfg)
			if err != nil {
				t.Fatalf("Error creating second durable consumer: %v", err)
			}

			// Now queue up some messages.
			for i := 11; i <= 20; i++ {
				sendStreamMsg(t, nc, "IK", fmt.Sprintf("M%d", i))
			}
			checkNumMsgs(20)
			checkSubPending(20)

			// Now make sure deleting the consumers will remove messages from
			// the stream since we are interest retention based.
			o.delete()
			checkNumMsgs(10)

			o2.delete()
			checkNumMsgs(0)
		})
	}
}

func TestJetStreamSystemLimits(t *testing.T) {
	s := RunRandClientPortServer(t)
	defer s.Shutdown()

	if _, _, err := s.JetStreamReservedResources(); err == nil {
		t.Fatalf("Expected error requesting jetstream reserved resources when not enabled")
	}
	// Create some accounts.
	facc, _ := s.LookupOrRegisterAccount("FOO")
	bacc, _ := s.LookupOrRegisterAccount("BAR")
	zacc, _ := s.LookupOrRegisterAccount("BAZ")

	jsconfig := &JetStreamConfig{MaxMemory: 1024, MaxStore: 8192, StoreDir: t.TempDir()}
	if err := s.EnableJetStream(jsconfig); err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}

	if rm, rd, err := s.JetStreamReservedResources(); err != nil {
		t.Fatalf("Unexpected error requesting jetstream reserved resources: %v", err)
	} else if rm != 0 || rd != 0 {
		t.Fatalf("Expected reserved memory and store to be 0, got %d and %d", rm, rd)
	}

	limits := func(mem int64, store int64) map[string]JetStreamAccountLimits {
		return map[string]JetStreamAccountLimits{
			_EMPTY_: {
				MaxMemory:    mem,
				MaxStore:     store,
				MaxStreams:   -1,
				MaxConsumers: -1,
			},
		}
	}

	if err := facc.EnableJetStream(limits(24, 192)); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	// Use up rest of our resources in memory
	if err := bacc.EnableJetStream(limits(1000, 0)); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// Now ask for more memory. Should error.
	if err := zacc.EnableJetStream(limits(1000, 0)); err == nil {
		t.Fatalf("Expected an error when exhausting memory resource limits")
	}
	// Disk too.
	if err := zacc.EnableJetStream(limits(0, 10000)); err == nil {
		t.Fatalf("Expected an error when exhausting memory resource limits")
	}
	facc.DisableJetStream()
	bacc.DisableJetStream()
	zacc.DisableJetStream()

	// Make sure we unreserved resources.
	if rm, rd, err := s.JetStreamReservedResources(); err != nil {
		t.Fatalf("Unexpected error requesting jetstream reserved resources: %v", err)
	} else if rm != 0 || rd != 0 {
		t.Fatalf("Expected reserved memory and store to be 0, got %v and %v", friendlyBytes(rm), friendlyBytes(rd))
	}

	if err := facc.EnableJetStream(limits(24, 192)); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	// Test Adjust
	lim := limits(jsconfig.MaxMemory, jsconfig.MaxStore)
	l := lim[_EMPTY_]
	l.MaxStreams = 10
	l.MaxConsumers = 10
	lim[_EMPTY_] = l
	if err := facc.UpdateJetStreamLimits(lim); err != nil {
		t.Fatalf("Unexpected error updating jetstream account limits: %v", err)
	}

	var msets []*stream
	// Now test max streams and max consumers. Note max consumers is per stream.
	for i := 0; i < 10; i++ {
		mname := fmt.Sprintf("foo.%d", i)
		mset, err := facc.addStream(&StreamConfig{Name: strconv.Itoa(i), Storage: MemoryStorage, Subjects: []string{mname}})
		if err != nil {
			t.Fatalf("Unexpected error adding stream: %v", err)
		}
		msets = append(msets, mset)
	}

	// Remove them all
	for _, mset := range msets {
		mset.delete()
	}

	// Now try to add one with bytes limit that would exceed the account limit.
	if _, err := facc.addStream(&StreamConfig{Name: "22", Storage: MemoryStorage, MaxBytes: jsconfig.MaxStore * 2}); err == nil {
		t.Fatalf("Expected error adding stream over limit")
	}

	// Replicas can't be > 1
	if _, err := facc.addStream(&StreamConfig{Name: "22", Storage: MemoryStorage, Replicas: 10}); err == nil {
		t.Fatalf("Expected error adding stream over limit")
	}

	// Test consumers limit against account limit when the stream does not set a limit
	mset, err := facc.addStream(&StreamConfig{Name: "22", Storage: MemoryStorage, Subjects: []string{"foo.22"}})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	for i := 0; i < 10; i++ {
		oname := fmt.Sprintf("O:%d", i)
		_, err := mset.addConsumer(&ConsumerConfig{Durable: oname, AckPolicy: AckExplicit})
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
	}

	// This one should fail.
	if _, err := mset.addConsumer(&ConsumerConfig{Durable: "O:22", AckPolicy: AckExplicit}); err == nil {
		t.Fatalf("Expected error adding consumer over the limit")
	}

	// Test consumer limit against stream limit
	mset.delete()
	mset, err = facc.addStream(&StreamConfig{Name: "22", Storage: MemoryStorage, Subjects: []string{"foo.22"}, MaxConsumers: 5})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	for i := 0; i < 5; i++ {
		oname := fmt.Sprintf("O:%d", i)
		_, err := mset.addConsumer(&ConsumerConfig{Durable: oname, AckPolicy: AckExplicit})
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
	}

	// This one should fail.
	if _, err := mset.addConsumer(&ConsumerConfig{Durable: "O:22", AckPolicy: AckExplicit}); err == nil {
		t.Fatalf("Expected error adding consumer over the limit")
	}

	// Test the account having smaller limits than the stream
	mset.delete()

	mset, err = facc.addStream(&StreamConfig{Name: "22", Storage: MemoryStorage, Subjects: []string{"foo.22"}, MaxConsumers: 10})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	l.MaxConsumers = 5
	lim[_EMPTY_] = l
	if err := facc.UpdateJetStreamLimits(lim); err != nil {
		t.Fatalf("Unexpected error updating jetstream account limits: %v", err)
	}

	for i := 0; i < 5; i++ {
		oname := fmt.Sprintf("O:%d", i)
		_, err := mset.addConsumer(&ConsumerConfig{Durable: oname, AckPolicy: AckExplicit})
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
	}

	// This one should fail.
	if _, err := mset.addConsumer(&ConsumerConfig{Durable: "O:22", AckPolicy: AckExplicit}); err == nil {
		t.Fatalf("Expected error adding consumer over the limit")
	}
}

func TestJetStreamSystemLimitsPlacement(t *testing.T) {
	const smallSystemLimit = 128
	const mediumSystemLimit = smallSystemLimit * 2
	const largeSystemLimit = smallSystemLimit * 3

	tmpl := `
		listen: 127.0.0.1:-1
		server_name: %s
		jetstream: {
			max_mem_store: _MAXMEM_
			max_file_store: _MAXFILE_
			store_dir: '%s'
		}

		server_tags: [
			_TAG_
		]

		leaf {
			listen: 127.0.0.1:-1
		}
		cluster {
			name: %s
			listen: 127.0.0.1:%d
			routes = [%s]
		}
		accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } }
	`
	storeCnf := func(serverName, clusterName, storeDir, conf string) string {
		switch serverName {
		case "S-1":
			conf = strings.Replace(conf, "_MAXMEM_", fmt.Sprint(smallSystemLimit), 1)
			conf = strings.Replace(conf, "_MAXFILE_", fmt.Sprint(smallSystemLimit), 1)
			return strings.Replace(conf, "_TAG_", "small", 1)
		case "S-2":
			conf = strings.Replace(conf, "_MAXMEM_", fmt.Sprint(mediumSystemLimit), 1)
			conf = strings.Replace(conf, "_MAXFILE_", fmt.Sprint(mediumSystemLimit), 1)
			return strings.Replace(conf, "_TAG_", "medium", 1)
		case "S-3":
			conf = strings.Replace(conf, "_MAXMEM_", fmt.Sprint(largeSystemLimit), 1)
			conf = strings.Replace(conf, "_MAXFILE_", fmt.Sprint(largeSystemLimit), 1)
			return strings.Replace(conf, "_TAG_", "large", 1)
		default:
			return conf
		}
	}

	cluster := createJetStreamClusterWithTemplateAndModHook(t, tmpl, "cluster-a", 3, storeCnf)
	defer cluster.shutdown()

	requestLeaderStepDown := func(clientURL string) error {
		nc, err := nats.Connect(clientURL, nats.UserInfo("admin", "s3cr3t!"))
		if err != nil {
			return err
		}
		defer nc.Close()

		ncResp, err := nc.Request(JSApiLeaderStepDown, nil, 3*time.Second)
		if err != nil {
			return err
		}

		var resp JSApiLeaderStepDownResponse
		if err := json.Unmarshal(ncResp.Data, &resp); err != nil {
			return err
		}
		if resp.Error != nil {
			return resp.Error
		}
		if !resp.Success {
			return fmt.Errorf("leader step down request not successful")
		}

		return nil
	}

	largeSrv := cluster.servers[2]
	// Force large server to be leader
	err := checkForErr(15*time.Second, 500*time.Millisecond, func() error {
		if largeSrv.JetStreamIsLeader() {
			return nil
		}

		if err := requestLeaderStepDown(largeSrv.ClientURL()); err != nil {
			return err
		}
		return fmt.Errorf("large server is not leader")
	})
	if err != nil {
		t.Skipf("failed to get desired layout: %s", err)
	}

	nc, js := jsClientConnect(t, largeSrv)
	defer nc.Close()

	cases := []struct {
		name           string
		storage        nats.StorageType
		createMaxBytes int64
		serverTag      string
		wantErr        bool
	}{
		{
			name:           "file create large stream on small server",
			storage:        nats.FileStorage,
			createMaxBytes: largeSystemLimit,
			serverTag:      "small",
			wantErr:        true,
		},
		{
			name:           "memory create large stream on small server",
			storage:        nats.MemoryStorage,
			createMaxBytes: largeSystemLimit,
			serverTag:      "small",
			wantErr:        true,
		},
		{
			name:           "file create large stream on medium server",
			storage:        nats.FileStorage,
			createMaxBytes: largeSystemLimit,
			serverTag:      "medium",
			wantErr:        true,
		},
		{
			name:           "memory create large stream on medium server",
			storage:        nats.MemoryStorage,
			createMaxBytes: largeSystemLimit,
			serverTag:      "medium",
			wantErr:        true,
		},
		{
			name:           "file create large stream on large server",
			storage:        nats.FileStorage,
			createMaxBytes: largeSystemLimit,
			serverTag:      "large",
		},
		{
			name:           "memory create large stream on large server",
			storage:        nats.MemoryStorage,
			createMaxBytes: largeSystemLimit,
			serverTag:      "large",
		},
	}

	for i := 0; i < len(cases) && !t.Failed(); i++ {
		c := cases[i]
		t.Run(c.name, func(st *testing.T) {
			_, err := js.AddStream(&nats.StreamConfig{
				Name:     "TEST",
				Subjects: []string{"foo"},
				Storage:  c.storage,
				MaxBytes: c.createMaxBytes,
				Placement: &nats.Placement{
					Cluster: "cluster-a",
					Tags:    []string{c.serverTag},
				},
			})
			if c.wantErr && err == nil {
				st.Fatalf("unexpected stream create success, maxBytes=%d, tag=%s",
					c.createMaxBytes, c.serverTag)
			} else if !c.wantErr && err != nil {
				st.Fatalf("unexpected error: %s", err)
			}

			if err == nil {
				err = js.DeleteStream("TEST")
				require_NoError(st, err)
			}
		})
	}

	// These next two tests should fail because although the stream fits in the
	// large and medium server, it doesn't fit on the small server.
	si, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
		Storage:  nats.FileStorage,
		MaxBytes: smallSystemLimit + 1,
		Replicas: 3,
	})
	if err == nil {
		t.Fatalf("unexpected file stream create success, maxBytes=%d, replicas=%d",
			si.Config.MaxBytes, si.Config.Replicas)
	}

	si, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
		Storage:  nats.MemoryStorage,
		MaxBytes: smallSystemLimit + 1,
		Replicas: 3,
	})
	if err == nil {
		t.Fatalf("unexpected memory stream create success, maxBytes=%d, replicas=%d",
			si.Config.MaxBytes, si.Config.Replicas)
	}

	t.Run("meta info placement in request - empty request", func(t *testing.T) {
		nc, err = nats.Connect(largeSrv.ClientURL(), nats.UserInfo("admin", "s3cr3t!"))
		require_NoError(t, err)
		defer nc.Close()

		var resp JSApiLeaderStepDownResponse
		ncResp, err := nc.Request(JSApiLeaderStepDown, []byte("{}"), 3*time.Second)
		require_NoError(t, err)
		err = json.Unmarshal(ncResp.Data, &resp)
		require_NoError(t, err)
		require_True(t, resp.Error == nil)
		require_True(t, resp.Success)

	})

	t.Run("meta info placement in request - uninitialized fields", func(t *testing.T) {
		nc, err = nats.Connect(largeSrv.ClientURL(), nats.UserInfo("admin", "s3cr3t!"))
		require_NoError(t, err)
		defer nc.Close()

		cluster.waitOnClusterReadyWithNumPeers(3)
		var resp JSApiLeaderStepDownResponse
		req, err := json.Marshal(JSApiLeaderStepdownRequest{Placement: nil})
		require_NoError(t, err)
		ncResp, err := nc.Request(JSApiLeaderStepDown, req, 10*time.Second)
		require_NoError(t, err)
		err = json.Unmarshal(ncResp.Data, &resp)
		require_NoError(t, err)
		require_True(t, resp.Error == nil)
	})

}

func TestJetStreamStreamLimitUpdate(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	err := s.GlobalAccount().UpdateJetStreamLimits(map[string]JetStreamAccountLimits{
		_EMPTY_: {
			MaxMemory:  128,
			MaxStore:   128,
			MaxStreams: 1,
		},
	})
	require_NoError(t, err)

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	for _, storage := range []nats.StorageType{nats.MemoryStorage, nats.FileStorage} {
		cfg := &nats.StreamConfig{
			Name:     "TEST",
			Subjects: []string{"foo"},
			Storage:  storage,
			MaxBytes: 32,
		}

		_, err = js.AddStream(cfg)
		require_NoError(t, err)

		// Create with same config is idempotent, and must not exceed max streams as it already exists.
		_, err = js.AddStream(cfg)
		require_NoError(t, err)

		cfg.MaxBytes = 16
		_, err = js.UpdateStream(cfg)
		require_NoError(t, err)

		require_NoError(t, js.DeleteStream("TEST"))
	}
}

func TestJetStreamStreamStorageTrackingAndLimits(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	gacc := s.GlobalAccount()

	al := map[string]JetStreamAccountLimits{
		_EMPTY_: {
			MaxMemory:    8192,
			MaxStore:     -1,
			MaxStreams:   -1,
			MaxConsumers: -1,
		},
	}

	if err := gacc.UpdateJetStreamLimits(al); err != nil {
		t.Fatalf("Unexpected error updating jetstream account limits: %v", err)
	}

	mset, err := gacc.addStream(&StreamConfig{Name: "LIMITS", Storage: MemoryStorage, Retention: WorkQueuePolicy})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	toSend := 100
	for i := 0; i < toSend; i++ {
		sendStreamMsg(t, nc, "LIMITS", "Hello World!")
	}

	state := mset.state()
	usage := gacc.JetStreamUsage()

	// Make sure these are working correctly.
	if state.Bytes != usage.Memory {
		t.Fatalf("Expected to have stream bytes match memory usage, %d vs %d", state.Bytes, usage.Memory)
	}
	if usage.Streams != 1 {
		t.Fatalf("Expected to have 1 stream, got %d", usage.Streams)
	}

	// Do second stream.
	mset2, err := gacc.addStream(&StreamConfig{Name: "NUM22", Storage: MemoryStorage, Retention: WorkQueuePolicy})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset2.delete()

	for i := 0; i < toSend; i++ {
		sendStreamMsg(t, nc, "NUM22", "Hello World!")
	}

	stats2 := mset2.state()
	usage = gacc.JetStreamUsage()

	if usage.Memory != (state.Bytes + stats2.Bytes) {
		t.Fatalf("Expected to track both streams, account is %v, stream1 is %v, stream2 is %v", usage.Memory, state.Bytes, stats2.Bytes)
	}

	// Make sure delete works.
	mset2.delete()
	stats2 = mset2.state()
	usage = gacc.JetStreamUsage()

	if usage.Memory != (state.Bytes + stats2.Bytes) {
		t.Fatalf("Expected to track both streams, account is %v, stream1 is %v, stream2 is %v", usage.Memory, state.Bytes, stats2.Bytes)
	}

	// Now drain the first one by consuming the messages.
	o, err := mset.addConsumer(workerModeConfig("WQ"))
	if err != nil {
		t.Fatalf("Expected no error with registered interest, got %v", err)
	}
	defer o.delete()

	for i := 0; i < toSend; i++ {
		msg, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		msg.Respond(nil)
	}
	nc.Flush()

	state = mset.state()
	checkFor(t, time.Second, 15*time.Millisecond, func() error {
		usage = gacc.JetStreamUsage()
		if usage.Memory != 0 {
			return fmt.Errorf("Expected usage memory to be 0, got %d", usage.Memory)
		}
		return nil
	})

	// Now send twice the number of messages. Should receive an error at some point, and we will check usage against limits.
	var errSeen string
	for i := 0; i < toSend*2; i++ {
		resp, _ := nc.Request("LIMITS", []byte("The quick brown fox jumped over the..."), 50*time.Millisecond)
		if string(resp.Data) != OK {
			errSeen = string(resp.Data)
			break
		}
	}

	if errSeen == "" {
		t.Fatalf("Expected to see an error when exceeding the account limits")
	}

	state = mset.state()
	var lim JetStreamAccountLimits
	checkFor(t, time.Second, 15*time.Millisecond, func() error {
		usage = gacc.JetStreamUsage()
		lim = al[_EMPTY_]
		if usage.Memory > uint64(lim.MaxMemory) {
			return fmt.Errorf("Expected memory to not exceed limit of %d, got %d", lim.MaxMemory, usage.Memory)
		}
		return nil
	})

	// make sure that unlimited accounts work
	lim.MaxMemory = -1

	if err := gacc.UpdateJetStreamLimits(al); err != nil {
		t.Fatalf("Unexpected error updating jetstream account limits: %v", err)
	}

	for i := 0; i < toSend; i++ {
		sendStreamMsg(t, nc, "LIMITS", "Hello World!")
	}
}

func TestJetStreamStreamFileTrackingAndLimits(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	gacc := s.GlobalAccount()

	al := map[string]JetStreamAccountLimits{
		_EMPTY_: {
			MaxMemory:    8192,
			MaxStore:     9600,
			MaxStreams:   -1,
			MaxConsumers: -1,
		},
	}

	if err := gacc.UpdateJetStreamLimits(al); err != nil {
		t.Fatalf("Unexpected error updating jetstream account limits: %v", err)
	}

	mconfig := &StreamConfig{Name: "LIMITS", Storage: FileStorage, Retention: WorkQueuePolicy}
	mset, err := gacc.addStream(mconfig)
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	toSend := 100
	for i := 0; i < toSend; i++ {
		sendStreamMsg(t, nc, "LIMITS", "Hello World!")
	}

	state := mset.state()
	usage := gacc.JetStreamUsage()

	// Make sure these are working correctly.
	if usage.Store != state.Bytes {
		t.Fatalf("Expected to have stream bytes match the store usage, %d vs %d", usage.Store, state.Bytes)
	}
	if usage.Streams != 1 {
		t.Fatalf("Expected to have 1 stream, got %d", usage.Streams)
	}

	// Do second stream.
	mconfig2 := &StreamConfig{Name: "NUM22", Storage: FileStorage, Retention: WorkQueuePolicy}
	mset2, err := gacc.addStream(mconfig2)
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset2.delete()

	for i := 0; i < toSend; i++ {
		sendStreamMsg(t, nc, "NUM22", "Hello World!")
	}

	stats2 := mset2.state()
	usage = gacc.JetStreamUsage()

	if usage.Store != (state.Bytes + stats2.Bytes) {
		t.Fatalf("Expected to track both streams, usage is %v, stream1 is %v, stream2 is %v", usage.Store, state.Bytes, stats2.Bytes)
	}

	// Make sure delete works.
	mset2.delete()
	stats2 = mset2.state()
	usage = gacc.JetStreamUsage()

	if usage.Store != (state.Bytes + stats2.Bytes) {
		t.Fatalf("Expected to track both streams, account is %v, stream1 is %v, stream2 is %v", usage.Store, state.Bytes, stats2.Bytes)
	}

	// Now drain the first one by consuming the messages.
	o, err := mset.addConsumer(workerModeConfig("WQ"))
	if err != nil {
		t.Fatalf("Expected no error with registered interest, got %v", err)
	}
	defer o.delete()

	for i := 0; i < toSend; i++ {
		msg, err := nc.Request(o.requestNextMsgSubject(), nil, time.Second)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		msg.Respond(nil)
	}
	nc.Flush()

	state = mset.state()
	usage = gacc.JetStreamUsage()

	if usage.Memory != 0 {
		t.Fatalf("Expected usage memeory to be 0, got %d", usage.Memory)
	}

	// Now send twice the number of messages. Should receive an error at some point, and we will check usage against limits.
	var errSeen string
	for i := 0; i < toSend*2; i++ {
		resp, _ := nc.Request("LIMITS", []byte("The quick brown fox jumped over the..."), 50*time.Millisecond)
		if string(resp.Data) != OK {
			errSeen = string(resp.Data)
			break
		}
	}

	if errSeen == "" {
		t.Fatalf("Expected to see an error when exceeding the account limits")
	}

	state = mset.state()
	usage = gacc.JetStreamUsage()

	lim := al[_EMPTY_]
	if usage.Memory > uint64(lim.MaxMemory) {
		t.Fatalf("Expected memory to not exceed limit of %d, got %d", lim.MaxMemory, usage.Memory)
	}
}

func TestJetStreamTieredLimits(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	gacc := s.GlobalAccount()

	tFail := map[string]JetStreamAccountLimits{
		"nottheer": {
			MaxMemory:    8192,
			MaxStore:     9600,
			MaxStreams:   -1,
			MaxConsumers: -1,
		},
	}

	if err := gacc.UpdateJetStreamLimits(tFail); err != nil {
		t.Fatalf("Unexpected error updating jetstream account limits: %v", err)
	}

	mconfig := &StreamConfig{Name: "LIMITS", Storage: FileStorage, Retention: WorkQueuePolicy}
	mset, err := gacc.addStream(mconfig)
	defer mset.delete()
	require_Error(t, err)
	require_Contains(t, err.Error(), "no JetStream default or applicable tiered limit present")

	tPass := map[string]JetStreamAccountLimits{
		"R1": {
			MaxMemory:    8192,
			MaxStore:     9600,
			MaxStreams:   -1,
			MaxConsumers: -1,
		},
	}

	if err := gacc.UpdateJetStreamLimits(tPass); err != nil {
		t.Fatalf("Unexpected error updating jetstream account limits: %v", err)
	}
}

type obsi struct {
	cfg ConsumerConfig
	ack int
}

type info struct {
	cfg   StreamConfig
	state StreamState
	obs   []obsi
}

func TestJetStreamSimpleFileRecovery(t *testing.T) {
	base := runtime.NumGoroutine()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()

	ostate := make(map[string]info)

	nid := nuid.New()
	randomSubject := func() string {
		nid.RandomizePrefix()
		return fmt.Sprintf("SUBJ.%s", nid.Next())
	}

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	numStreams := 10
	for i := 1; i <= numStreams; i++ {
		msetName := fmt.Sprintf("MMS-%d", i)
		subjects := []string{randomSubject(), randomSubject(), randomSubject()}
		msetConfig := StreamConfig{
			Name:     msetName,
			Storage:  FileStorage,
			Subjects: subjects,
			MaxMsgs:  100,
		}
		mset, err := acc.addStream(&msetConfig)
		if err != nil {
			t.Fatalf("Unexpected error adding stream %q: %v", msetName, err)
		}

		toSend := rand.Intn(100) + 1
		for n := 1; n <= toSend; n++ {
			msg := fmt.Sprintf("Hello %d", n*i)
			subj := subjects[rand.Intn(len(subjects))]
			sendStreamMsg(t, nc, subj, msg)
		}
		// Create up to 5 consumers.
		numObs := rand.Intn(5) + 1
		var obs []obsi
		for n := 1; n <= numObs; n++ {
			oname := fmt.Sprintf("WQ-%d-%d", i, n)
			o, err := mset.addConsumer(workerModeConfig(oname))
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			// Now grab some messages.
			toReceive := rand.Intn(toSend) + 1
			rsubj := o.requestNextMsgSubject()
			for r := 0; r < toReceive; r++ {
				resp, err := nc.Request(rsubj, nil, time.Second)
				require_NoError(t, err)
				if resp != nil {
					resp.Respond(nil)
				}
			}
			obs = append(obs, obsi{o.config(), toReceive})
		}
		ostate[msetName] = info{mset.config(), mset.state(), obs}
	}
	pusage := acc.JetStreamUsage()
	nc.Flush()

	// Shutdown and restart and make sure things come back.
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()

	checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
		delta := (runtime.NumGoroutine() - base)
		if delta > 3 {
			return fmt.Errorf("%d Go routines still exist post Shutdown()", delta)
		}
		return nil
	})

	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	acc = s.GlobalAccount()

	nusage := acc.JetStreamUsage()
	if !reflect.DeepEqual(nusage, pusage) {
		t.Fatalf("Usage does not match after restore: %+v vs %+v", nusage, pusage)
	}

	for mname, info := range ostate {
		mset, err := acc.lookupStream(mname)
		if err != nil {
			t.Fatalf("Expected to find a stream for %q", mname)
		}
		if state := mset.state(); !reflect.DeepEqual(state, info.state) {
			t.Fatalf("State does not match: %+v vs %+v", state, info.state)
		}
		if cfg := mset.config(); !reflect.DeepEqual(cfg, info.cfg) {
			t.Fatalf("Configs do not match: %+v vs %+v", cfg, info.cfg)
		}
		// Consumers.
		if mset.numConsumers() != len(info.obs) {
			t.Fatalf("Number of consumers do not match: %d vs %d", mset.numConsumers(), len(info.obs))
		}
		for _, oi := range info.obs {
			if o := mset.lookupConsumer(oi.cfg.Durable); o != nil {
				if uint64(oi.ack+1) != o.nextSeq() {
					t.Fatalf("Consumer next seq is not correct: %d vs %d", oi.ack+1, o.nextSeq())
				}
			} else {
				t.Fatalf("Expected to get an consumer")
			}
		}
	}
}

func TestJetStreamPushConsumerFlowControl(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST"}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	sub, err := nc.SubscribeSync(nats.NewInbox())
	require_NoError(t, err)
	defer sub.Unsubscribe()

	obsReq := CreateConsumerRequest{
		Stream: "TEST",
		Config: ConsumerConfig{
			Durable:        "dlc",
			DeliverSubject: sub.Subject,
			FlowControl:    true,
			Heartbeat:      5 * time.Second,
		},
	}
	req, err := json.Marshal(obsReq)
	require_NoError(t, err)
	resp, err := nc.Request(fmt.Sprintf(JSApiDurableCreateT, "TEST", "dlc"), req, time.Second)
	require_NoError(t, err)
	var ccResp JSApiConsumerCreateResponse
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if ccResp.Error != nil {
		t.Fatalf("Unexpected error: %+v", ccResp.Error)
	}

	// Grab the low level consumer so we can manually set the fc max.
	if mset, err := s.GlobalAccount().lookupStream("TEST"); err != nil {
		t.Fatalf("Error looking up stream: %v", err)
	} else if obs := mset.lookupConsumer("dlc"); obs == nil {
		t.Fatalf("Error looking up stream: %v", err)
	} else {
		obs.mu.Lock()
		obs.setMaxPendingBytes(16 * 1024)
		obs.mu.Unlock()
	}

	msgSize := 1024
	msg := make([]byte, msgSize)
	crand.Read(msg)

	sendBatch := func(n int) {
		for i := 0; i < n; i++ {
			if _, err := js.Publish("TEST", msg); err != nil {
				t.Fatalf("Unexpected publish error: %v", err)
			}
		}
	}

	checkSubPending := func(numExpected int) {
		t.Helper()
		checkFor(t, time.Second, 100*time.Millisecond, func() error {
			if nmsgs, _, err := sub.Pending(); err != nil || nmsgs != numExpected {
				return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, numExpected)
			}
			return nil
		})
	}

	sendBatch(100)
	checkSubPending(2) // First four data and flowcontrol from slow start pause.

	var n int
	for m, err := sub.NextMsg(time.Second); err == nil; m, err = sub.NextMsg(time.Second) {
		if m.Subject == "TEST" {
			n++
		} else {
			// This should be a FC control message.
			if m.Header.Get("Status") != "100" {
				t.Fatalf("Expected a 100 status code, got %q", m.Header.Get("Status"))
			}
			if m.Header.Get("Description") != "FlowControl Request" {
				t.Fatalf("Wrong description, got %q", m.Header.Get("Description"))
			}
			m.Respond(nil)
		}
	}

	if n != 100 {
		t.Fatalf("Expected to receive all 100 messages but got %d", n)
	}
}

func TestJetStreamFlowControlRequiresHeartbeats(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST"}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	if _, err := js.AddConsumer("TEST", &nats.ConsumerConfig{
		Durable:        "dlc",
		DeliverSubject: nats.NewInbox(),
		FlowControl:    true,
	}); err == nil || IsNatsErr(err, JSConsumerWithFlowControlNeedsHeartbeats) {
		t.Fatalf("Unexpected error: %v", err)
	}
}

func TestJetStreamPushConsumerIdleHeartbeats(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST"}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	sub, err := nc.SubscribeSync(nats.NewInbox())
	require_NoError(t, err)
	defer sub.Unsubscribe()

	// Test errors first
	obsReq := CreateConsumerRequest{
		Stream: "TEST",
		Config: ConsumerConfig{
			DeliverSubject: sub.Subject,
			Heartbeat:      time.Millisecond,
		},
	}
	req, err := json.Marshal(obsReq)
	require_NoError(t, err)
	resp, err := nc.Request(fmt.Sprintf(JSApiConsumerCreateT, "TEST"), req, time.Second)
	require_NoError(t, err)
	var ccResp JSApiConsumerCreateResponse
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if ccResp.Error == nil {
		t.Fatalf("Expected an error, got none")
	}
	// Set acceptable heartbeat.
	obsReq.Config.Heartbeat = 100 * time.Millisecond
	req, err = json.Marshal(obsReq)
	require_NoError(t, err)
	resp, err = nc.Request(fmt.Sprintf(JSApiConsumerCreateT, "TEST"), req, time.Second)
	require_NoError(t, err)
	ccResp.Error = nil
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	checkFor(t, time.Second, 20*time.Millisecond, func() error {
		if nmsgs, _, err := sub.Pending(); err != nil || nmsgs < 9 {
			return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, 9)
		}
		return nil
	})
	m, _ := sub.NextMsg(0)
	if m.Header.Get("Status") != "100" {
		t.Fatalf("Expected a 100 status code, got %q", m.Header.Get("Status"))
	}
	if m.Header.Get("Description") != "Idle Heartbeat" {
		t.Fatalf("Wrong description, got %q", m.Header.Get("Description"))
	}
}

func TestJetStreamPushConsumerIdleHeartbeatsWithFilterSubject(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST", Subjects: []string{"foo", "bar"}}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	hbC := make(chan *nats.Msg, 8)
	sub, err := nc.ChanSubscribe(nats.NewInbox(), hbC)
	require_NoError(t, err)
	defer sub.Unsubscribe()

	obsReq := CreateConsumerRequest{
		Stream: "TEST",
		Config: ConsumerConfig{
			DeliverSubject: sub.Subject,
			FilterSubject:  "bar",
			Heartbeat:      100 * time.Millisecond,
		},
	}

	req, err := json.Marshal(obsReq)
	require_NoError(t, err)
	resp, err := nc.Request(fmt.Sprintf(JSApiConsumerCreateT, "TEST"), req, time.Second)
	require_NoError(t, err)
	var ccResp JSApiConsumerCreateResponse
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	st := time.NewTicker(10 * time.Millisecond)
	defer st.Stop()

	done := time.NewTimer(time.Second)
	defer done.Stop()

	for {
		select {
		case <-st.C:
			js.Publish("foo", []byte("HELLO FOO"))
		case <-done.C:
			t.Fatalf("Expected to have seen idle heartbeats for consumer")
		case <-hbC:
			return
		}
	}
}

func TestJetStreamPushConsumerIdleHeartbeatsWithNoInterest(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST"}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	dsubj := "d.22"
	hbC := make(chan *nats.Msg, 8)
	sub, err := nc.ChanSubscribe("d.>", hbC)
	require_NoError(t, err)
	defer sub.Unsubscribe()

	obsReq := CreateConsumerRequest{
		Stream: "TEST",
		Config: ConsumerConfig{
			DeliverSubject: dsubj,
			Heartbeat:      100 * time.Millisecond,
		},
	}

	req, err := json.Marshal(obsReq)
	require_NoError(t, err)
	resp, err := nc.Request(fmt.Sprintf(JSApiConsumerCreateT, "TEST"), req, time.Second)
	require_NoError(t, err)
	var ccResp JSApiConsumerCreateResponse
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if ccResp.Error != nil {
		t.Fatalf("Unexpected error: %+v", ccResp.Error)
	}

	done := time.NewTimer(400 * time.Millisecond)
	defer done.Stop()

	for {
		select {
		case <-done.C:
			return
		case m := <-hbC:
			if m.Header.Get("Status") == "100" {
				t.Fatalf("Did not expect to see a heartbeat with no formal interest")
			}
		}
	}
}

func TestJetStreamInfoAPIWithHeaders(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc := clientConnectToServer(t, s)
	defer nc.Close()

	m := nats.NewMsg(JSApiAccountInfo)
	m.Header.Add("Accept-Encoding", "json")
	m.Header.Add("Authorization", "s3cr3t")
	m.Data = []byte("HELLO-JS!")

	resp, err := nc.RequestMsg(m, time.Second)
	require_NoError(t, err)

	var info JSApiAccountInfoResponse
	if err := json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if info.Error != nil {
		t.Fatalf("Received an error: %+v", info.Error)
	}
}

func TestJetStreamRequestAPI(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc := clientConnectToServer(t, s)
	defer nc.Close()

	// This will get the current information about usage and limits for this account.
	resp, err := nc.Request(JSApiAccountInfo, nil, time.Second)
	require_NoError(t, err)
	var info JSApiAccountInfoResponse
	if err := json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// JS API level should be set.
	require_Equal(t, info.API.Level, JSApiLevel)

	// Now create a stream.
	msetCfg := StreamConfig{
		Name:     "MSET22",
		Storage:  FileStorage,
		Subjects: []string{"foo", "bar", "baz"},
		MaxMsgs:  100,
	}
	req, err := json.Marshal(msetCfg)
	require_NoError(t, err)
	resp, _ = nc.Request(fmt.Sprintf(JSApiStreamCreateT, msetCfg.Name), req, time.Second)
	var scResp JSApiStreamCreateResponse
	if err := json.Unmarshal(resp.Data, &scResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if scResp.StreamInfo == nil || scResp.Error != nil {
		t.Fatalf("Did not receive correct response: %+v", scResp.Error)
	}
	if time.Since(scResp.Created) > time.Second {
		t.Fatalf("Created time seems wrong: %v\n", scResp.Created)
	}

	// Check that the name in config has to match the name in the subject
	resp, _ = nc.Request(fmt.Sprintf(JSApiStreamCreateT, "BOB"), req, time.Second)
	scResp.Error, scResp.StreamInfo = nil, nil
	if err := json.Unmarshal(resp.Data, &scResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	checkNatsError(t, scResp.Error, JSStreamMismatchErr)

	// Check that update works.
	msetCfg.Subjects = []string{"foo", "bar", "baz"}
	msetCfg.MaxBytes = 2222222
	req, err = json.Marshal(msetCfg)
	require_NoError(t, err)
	resp, _ = nc.Request(fmt.Sprintf(JSApiStreamUpdateT, msetCfg.Name), req, time.Second)
	scResp.Error, scResp.StreamInfo = nil, nil
	if err := json.Unmarshal(resp.Data, &scResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if scResp.StreamInfo == nil || scResp.Error != nil {
		t.Fatalf("Did not receive correct response: %+v", scResp.Error)
	}

	// Check that updating a non existing stream fails
	cfg := StreamConfig{
		Name:     "UNKNOWN_STREAM",
		Storage:  FileStorage,
		Subjects: []string{"foo"},
	}
	req, err = json.Marshal(cfg)
	require_NoError(t, err)
	resp, _ = nc.Request(fmt.Sprintf(JSApiStreamUpdateT, cfg.Name), req, time.Second)
	scResp.Error, scResp.StreamInfo = nil, nil
	if err := json.Unmarshal(resp.Data, &scResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if scResp.StreamInfo != nil || scResp.Error == nil || scResp.Error.Code != 404 {
		t.Fatalf("Unexpected error: %+v", scResp.Error)
	}

	// Now lookup info again and see that we can see the new stream.
	resp, err = nc.Request(JSApiAccountInfo, nil, time.Second)
	require_NoError(t, err)
	if err = json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if info.Streams != 1 {
		t.Fatalf("Expected to see 1 Stream, got %d", info.Streams)
	}

	// Make sure list names works.
	resp, err = nc.Request(JSApiStreams, nil, time.Second)
	require_NoError(t, err)
	var namesResponse JSApiStreamNamesResponse
	if err = json.Unmarshal(resp.Data, &namesResponse); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	if len(namesResponse.Streams) != 1 {
		t.Fatalf("Expected only 1 stream but got %d", len(namesResponse.Streams))
	}
	if namesResponse.Total != 1 {
		t.Fatalf("Expected total to be 1 but got %d", namesResponse.Total)
	}
	if namesResponse.Offset != 0 {
		t.Fatalf("Expected offset to be 0 but got %d", namesResponse.Offset)
	}
	if namesResponse.Limit != JSApiNamesLimit {
		t.Fatalf("Expected limit to be %d but got %d", JSApiNamesLimit, namesResponse.Limit)
	}
	if namesResponse.Streams[0] != msetCfg.Name {
		t.Fatalf("Expected to get %q, but got %q", msetCfg.Name, namesResponse.Streams[0])
	}

	// Now do detailed version.
	resp, err = nc.Request(JSApiStreamList, nil, time.Second)
	require_NoError(t, err)
	var listResponse JSApiStreamListResponse
	if err = json.Unmarshal(resp.Data, &listResponse); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	if len(listResponse.Streams) != 1 {
		t.Fatalf("Expected only 1 stream but got %d", len(listResponse.Streams))
	}
	if listResponse.Total != 1 {
		t.Fatalf("Expected total to be 1 but got %d", listResponse.Total)
	}
	if listResponse.Offset != 0 {
		t.Fatalf("Expected offset to be 0 but got %d", listResponse.Offset)
	}
	if listResponse.Limit != JSApiListLimit {
		t.Fatalf("Expected limit to be %d but got %d", JSApiListLimit, listResponse.Limit)
	}
	if listResponse.Streams[0].Config.Name != msetCfg.Name {
		t.Fatalf("Expected to get %q, but got %q", msetCfg.Name, listResponse.Streams[0].Config.Name)
	}

	// Now send some messages, then we can poll for info on this stream.
	toSend := 10
	for i := 0; i < toSend; i++ {
		nc.Request("foo", []byte("WELCOME JETSTREAM"), time.Second)
	}

	resp, err = nc.Request(fmt.Sprintf(JSApiStreamInfoT, msetCfg.Name), nil, time.Second)
	require_NoError(t, err)
	var msi StreamInfo
	if err = json.Unmarshal(resp.Data, &msi); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if msi.State.Msgs != uint64(toSend) {
		t.Fatalf("Expected to get %d msgs, got %d", toSend, msi.State.Msgs)
	}
	if time.Since(msi.Created) > time.Second {
		t.Fatalf("Created time seems wrong: %v\n", msi.Created)
	}

	// Looking up one that is not there should yield an error.
	resp, err = nc.Request(fmt.Sprintf(JSApiStreamInfoT, "BOB"), nil, time.Second)
	require_NoError(t, err)
	var bResp JSApiStreamInfoResponse
	if err = json.Unmarshal(resp.Data, &bResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	checkNatsError(t, bResp.Error, JSStreamNotFoundErr)

	// Now create a consumer.
	delivery := nats.NewInbox()
	obsReq := CreateConsumerRequest{
		Stream: msetCfg.Name,
		Config: ConsumerConfig{DeliverSubject: delivery},
	}
	req, err = json.Marshal(obsReq)
	require_NoError(t, err)
	resp, err = nc.Request(fmt.Sprintf(JSApiConsumerCreateT, msetCfg.Name), req, time.Second)
	require_NoError(t, err)
	var ccResp JSApiConsumerCreateResponse
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	// Ephemerals are now not rejected when there is no interest.
	if ccResp.ConsumerInfo == nil || ccResp.Error != nil {
		t.Fatalf("Got a bad response %+v", ccResp)
	}
	if time.Since(ccResp.Created) > time.Second {
		t.Fatalf("Created time seems wrong: %v\n", ccResp.Created)
	}

	// Now create subscription and make sure we get proper response.
	sub, _ := nc.SubscribeSync(delivery)
	nc.Flush()

	checkFor(t, 250*time.Millisecond, 10*time.Millisecond, func() error {
		if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != toSend {
			return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, toSend)
		}
		return nil
	})

	// Check that we get an error if the stream name in the subject does not match the config.
	resp, err = nc.Request(fmt.Sprintf(JSApiConsumerCreateT, "BOB"), req, time.Second)
	require_NoError(t, err)
	ccResp.Error, ccResp.ConsumerInfo = nil, nil
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	// Since we do not have interest this should have failed.
	checkNatsError(t, ccResp.Error, JSStreamMismatchErr)

	// Get the list of all of the consumers for our stream.
	resp, err = nc.Request(fmt.Sprintf(JSApiConsumersT, msetCfg.Name), nil, time.Second)
	require_NoError(t, err)
	var clResponse JSApiConsumerNamesResponse
	if err = json.Unmarshal(resp.Data, &clResponse); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if len(clResponse.Consumers) != 1 {
		t.Fatalf("Expected only 1 consumer but got %d", len(clResponse.Consumers))
	}
	// Now let's get info about our consumer.
	cName := clResponse.Consumers[0]
	resp, err = nc.Request(fmt.Sprintf(JSApiConsumerInfoT, msetCfg.Name, cName), nil, time.Second)
	require_NoError(t, err)
	var oinfo ConsumerInfo
	if err = json.Unmarshal(resp.Data, &oinfo); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	// Do some sanity checking.
	// Must match consumer.go
	const randConsumerNameLen = 8
	if len(oinfo.Name) != randConsumerNameLen {
		t.Fatalf("Expected ephemeral name, got %q", oinfo.Name)
	}
	if len(oinfo.Config.Durable) != 0 {
		t.Fatalf("Expected no durable name, but got %q", oinfo.Config.Durable)
	}
	if oinfo.Config.DeliverSubject != delivery {
		t.Fatalf("Expected to have delivery subject of %q, got %q", delivery, oinfo.Config.DeliverSubject)
	}
	if oinfo.Delivered.Consumer != 10 {
		t.Fatalf("Expected consumer delivered sequence of 10, got %d", oinfo.Delivered.Consumer)
	}
	if oinfo.AckFloor.Consumer != 10 {
		t.Fatalf("Expected ack floor to be 10, got %d", oinfo.AckFloor.Consumer)
	}

	// Now delete the consumer.
	resp, _ = nc.Request(fmt.Sprintf(JSApiConsumerDeleteT, msetCfg.Name, cName), nil, time.Second)
	var cdResp JSApiConsumerDeleteResponse
	if err = json.Unmarshal(resp.Data, &cdResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if !cdResp.Success || cdResp.Error != nil {
		t.Fatalf("Got a bad response %+v", ccResp)
	}

	// Make sure we can't create a durable using the ephemeral API endpoint.
	obsReq = CreateConsumerRequest{
		Stream: msetCfg.Name,
		Config: ConsumerConfig{Durable: "myd", DeliverSubject: delivery},
	}
	req, err = json.Marshal(obsReq)
	require_NoError(t, err)
	resp, err = nc.Request(fmt.Sprintf(JSApiConsumerCreateT, msetCfg.Name), req, time.Second)
	require_NoError(t, err)
	ccResp.Error, ccResp.ConsumerInfo = nil, nil
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	checkNatsError(t, ccResp.Error, JSConsumerEphemeralWithDurableNameErr)

	// Now make sure we can create a durable on the subject with the proper name.
	resp, err = nc.Request(fmt.Sprintf(JSApiDurableCreateT, msetCfg.Name, obsReq.Config.Durable), req, time.Second)
	ccResp.Error, ccResp.ConsumerInfo = nil, nil
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if ccResp.ConsumerInfo == nil || ccResp.Error != nil {
		t.Fatalf("Did not receive correct response")
	}

	// Make sure empty durable in cfg does not work
	obsReq2 := CreateConsumerRequest{
		Stream: msetCfg.Name,
		Config: ConsumerConfig{DeliverSubject: delivery},
	}
	req2, err := json.Marshal(obsReq2)
	require_NoError(t, err)
	resp, err = nc.Request(fmt.Sprintf(JSApiDurableCreateT, msetCfg.Name, obsReq.Config.Durable), req2, time.Second)
	require_NoError(t, err)
	ccResp.Error, ccResp.ConsumerInfo = nil, nil
	if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	checkNatsError(t, ccResp.Error, JSConsumerDurableNameNotSetErr)

	// Now delete a msg.
	dreq := JSApiMsgDeleteRequest{Seq: 2}
	dreqj, err := json.Marshal(dreq)
	require_NoError(t, err)
	resp, _ = nc.Request(fmt.Sprintf(JSApiMsgDeleteT, msetCfg.Name), dreqj, time.Second)
	var delMsgResp JSApiMsgDeleteResponse
	if err = json.Unmarshal(resp.Data, &delMsgResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if !delMsgResp.Success || delMsgResp.Error != nil {
		t.Fatalf("Got a bad response %+v", delMsgResp.Error)
	}

	// Now purge the stream.
	resp, _ = nc.Request(fmt.Sprintf(JSApiStreamPurgeT, msetCfg.Name), nil, time.Second)
	var pResp JSApiStreamPurgeResponse
	if err = json.Unmarshal(resp.Data, &pResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if !pResp.Success || pResp.Error != nil {
		t.Fatalf("Got a bad response %+v", pResp)
	}
	if pResp.Purged != 9 {
		t.Fatalf("Expected 9 purged, got %d", pResp.Purged)
	}

	// Now delete the stream.
	resp, _ = nc.Request(fmt.Sprintf(JSApiStreamDeleteT, msetCfg.Name), nil, time.Second)
	var dResp JSApiStreamDeleteResponse
	if err = json.Unmarshal(resp.Data, &dResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if !dResp.Success || dResp.Error != nil {
		t.Fatalf("Got a bad response %+v", dResp.Error)
	}

	// Now grab stats again.
	// This will get the current information about usage and limits for this account.
	resp, err = nc.Request(JSApiAccountInfo, nil, time.Second)
	require_NoError(t, err)
	if err := json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if info.Streams != 0 {
		t.Fatalf("Expected no remaining streams, got %d", info.Streams)
	}

	// Now do templates.
	mcfg := &StreamConfig{
		Subjects:  []string{"kv.*"},
		Retention: LimitsPolicy,
		MaxAge:    time.Hour,
		MaxMsgs:   4,
		Storage:   MemoryStorage,
		Replicas:  1,
	}
	template := &StreamTemplateConfig{
		Name:       "kv",
		Config:     mcfg,
		MaxStreams: 4,
	}
	req, err = json.Marshal(template)
	require_NoError(t, err)

	// Check that the name in config has to match the name in the subject
	resp, _ = nc.Request(fmt.Sprintf(JSApiTemplateCreateT, "BOB"), req, time.Second)
	var stResp JSApiStreamTemplateCreateResponse
	if err = json.Unmarshal(resp.Data, &stResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	checkNatsError(t, stResp.Error, JSTemplateNameNotMatchSubjectErr)

	resp, _ = nc.Request(fmt.Sprintf(JSApiTemplateCreateT, template.Name), req, time.Second)
	stResp.Error, stResp.StreamTemplateInfo = nil, nil
	if err = json.Unmarshal(resp.Data, &stResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if stResp.StreamTemplateInfo == nil || stResp.Error != nil {
		t.Fatalf("Did not receive correct response")
	}

	// Create a second one.
	template.Name = "ss"
	template.Config.Subjects = []string{"foo", "bar"}

	req, err = json.Marshal(template)
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}

	resp, _ = nc.Request(fmt.Sprintf(JSApiTemplateCreateT, template.Name), req, time.Second)
	stResp.Error, stResp.StreamTemplateInfo = nil, nil
	if err = json.Unmarshal(resp.Data, &stResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if stResp.StreamTemplateInfo == nil || stResp.Error != nil {
		t.Fatalf("Did not receive correct response")
	}

	// Now grab the list of templates
	var tListResp JSApiStreamTemplateNamesResponse
	resp, err = nc.Request(JSApiTemplates, nil, time.Second)
	if err = json.Unmarshal(resp.Data, &tListResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if len(tListResp.Templates) != 2 {
		t.Fatalf("Expected 2 templates but got %d", len(tListResp.Templates))
	}
	slices.Sort(tListResp.Templates)
	if tListResp.Templates[0] != "kv" {
		t.Fatalf("Expected to get %q, but got %q", "kv", tListResp.Templates[0])
	}
	if tListResp.Templates[1] != "ss" {
		t.Fatalf("Expected to get %q, but got %q", "ss", tListResp.Templates[1])
	}

	// Now delete one.
	// Test bad name.
	resp, _ = nc.Request(fmt.Sprintf(JSApiTemplateDeleteT, "bob"), nil, time.Second)
	var tDeleteResp JSApiStreamTemplateDeleteResponse
	if err = json.Unmarshal(resp.Data, &tDeleteResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	checkNatsError(t, tDeleteResp.Error, JSStreamTemplateNotFoundErr)

	resp, _ = nc.Request(fmt.Sprintf(JSApiTemplateDeleteT, "ss"), nil, time.Second)
	tDeleteResp.Error = nil
	if err = json.Unmarshal(resp.Data, &tDeleteResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if !tDeleteResp.Success || tDeleteResp.Error != nil {
		t.Fatalf("Did not receive correct response: %+v", tDeleteResp.Error)
	}

	resp, err = nc.Request(JSApiTemplates, nil, time.Second)
	tListResp.Error, tListResp.Templates = nil, nil
	if err = json.Unmarshal(resp.Data, &tListResp); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if len(tListResp.Templates) != 1 {
		t.Fatalf("Expected 1 template but got %d", len(tListResp.Templates))
	}
	if tListResp.Templates[0] != "kv" {
		t.Fatalf("Expected to get %q, but got %q", "kv", tListResp.Templates[0])
	}

	// First create a stream from the template
	sendStreamMsg(t, nc, "kv.22", "derek")
	// Last do info
	resp, err = nc.Request(fmt.Sprintf(JSApiTemplateInfoT, "kv"), nil, time.Second)
	require_NoError(t, err)
	var ti StreamTemplateInfo
	if err = json.Unmarshal(resp.Data, &ti); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if len(ti.Streams) != 1 {
		t.Fatalf("Expected 1 stream, got %d", len(ti.Streams))
	}
	if ti.Streams[0] != canonicalName("kv.22") {
		t.Fatalf("Expected stream with name %q, but got %q", canonicalName("kv.22"), ti.Streams[0])
	}

	// Test that we can send nil or an empty legal json for requests that take no args.
	// We know this stream does not exist, this just checking request processing.
	checkEmptyReqArg := func(arg string) {
		t.Helper()
		var req []byte
		if len(arg) > 0 {
			req = []byte(arg)
		}
		resp, err = nc.Request(fmt.Sprintf(JSApiStreamDeleteT, "foo_bar_baz"), req, time.Second)
		var dResp JSApiStreamDeleteResponse
		if err = json.Unmarshal(resp.Data, &dResp); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if dResp.Error == nil || dResp.Error.Code != 404 {
			t.Fatalf("Got a bad response, expected a 404 response %+v", dResp.Error)
		}
	}

	checkEmptyReqArg("")
	checkEmptyReqArg("{}")
	checkEmptyReqArg(" {} ")
	checkEmptyReqArg(" { } ")
}

func TestJetStreamFilteredStreamNames(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc := clientConnectToServer(t, s)
	defer nc.Close()

	// Create some streams.
	var snid int
	createStream := func(subjects []string) {
		t.Helper()
		snid++
		name := fmt.Sprintf("S-%d", snid)
		sc := &StreamConfig{Name: name, Subjects: subjects}
		if _, err := s.GlobalAccount().addStream(sc); err != nil {
			t.Fatalf("Unexpected error adding stream: %v", err)
		}
	}

	createStream([]string{"foo"})                  // S1
	createStream([]string{"bar"})                  // S2
	createStream([]string{"baz"})                  // S3
	createStream([]string{"foo.*", "bar.*"})       // S4
	createStream([]string{"foo-1.22", "bar-1.33"}) // S5

	expectStreams := func(filter string, streams []string) {
		t.Helper()
		req, _ := json.Marshal(&JSApiStreamNamesRequest{Subject: filter})
		r, _ := nc.Request(JSApiStreams, req, time.Second)
		var resp JSApiStreamNamesResponse
		if err := json.Unmarshal(r.Data, &resp); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if len(resp.Streams) != len(streams) {
			t.Fatalf("Expected %d results, got %d", len(streams), len(resp.Streams))
		}
	}

	expectStreams("foo", []string{"S1"})
	expectStreams("bar", []string{"S2"})
	expectStreams("baz", []string{"S3"})
	expectStreams("*", []string{"S1", "S2", "S3"})
	expectStreams(">", []string{"S1", "S2", "S3", "S4", "S5"})
	expectStreams("*.*", []string{"S4", "S5"})
	expectStreams("*.22", []string{"S4", "S5"})
}

func TestJetStreamUpdateStream(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{name: "MemoryStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   MemoryStorage,
				Replicas:  1,
			}},
		{name: "FileStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   FileStorage,
				Replicas:  1,
			}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			// Test basic updates. We allow changing the subjects, limits, and no_ack along with replicas(TBD w/ cluster)
			cfg := *c.mconfig

			// Can't change name.
			cfg.Name = "bar"
			if err := mset.update(&cfg); err == nil || !strings.Contains(err.Error(), "name must match") {
				t.Fatalf("Expected error trying to update name")
			}
			// Can't change max consumers for now.
			cfg = *c.mconfig
			cfg.MaxConsumers = 10
			if err := mset.update(&cfg); err == nil || !strings.Contains(err.Error(), "can not change") {
				t.Fatalf("Expected error trying to change MaxConsumers")
			}
			// Can't change storage types.
			cfg = *c.mconfig
			if cfg.Storage == FileStorage {
				cfg.Storage = MemoryStorage
			} else {
				cfg.Storage = FileStorage
			}
			if err := mset.update(&cfg); err == nil || !strings.Contains(err.Error(), "can not change") {
				t.Fatalf("Expected error trying to change Storage")
			}
			// Can't change replicas > 1 for now.
			cfg = *c.mconfig
			cfg.Replicas = 10
			if err := mset.update(&cfg); err == nil || !strings.Contains(err.Error(), "maximum replicas") {
				t.Fatalf("Expected error trying to change Replicas")
			}
			// Can't have a template set for now.
			cfg = *c.mconfig
			cfg.Template = "baz"
			if err := mset.update(&cfg); err == nil || !strings.Contains(err.Error(), "template") {
				t.Fatalf("Expected error trying to change Template owner")
			}
			// Can't change limits policy.
			cfg = *c.mconfig
			cfg.Retention = WorkQueuePolicy
			if err := mset.update(&cfg); err == nil || !strings.Contains(err.Error(), "can not change") {
				t.Fatalf("Expected error trying to change Retention")
			}

			// Now test changing limits.
			nc := clientConnectToServer(t, s)
			defer nc.Close()

			pending := uint64(100)
			for i := uint64(0); i < pending; i++ {
				sendStreamMsg(t, nc, "foo", "0123456789")
			}
			pendingBytes := mset.state().Bytes

			checkPending := func(msgs, bts uint64) {
				t.Helper()
				state := mset.state()
				if state.Msgs != msgs {
					t.Fatalf("Expected %d messages, got %d", msgs, state.Msgs)
				}
				if state.Bytes != bts {
					t.Fatalf("Expected %d bytes, got %d", bts, state.Bytes)
				}
			}
			checkPending(pending, pendingBytes)

			// Update msgs to higher.
			cfg = *c.mconfig
			cfg.MaxMsgs = int64(pending * 2)
			if err := mset.update(&cfg); err != nil {
				t.Fatalf("Unexpected error %v", err)
			}
			if mset.config().MaxMsgs != cfg.MaxMsgs {
				t.Fatalf("Expected the change to take effect, %d vs %d", mset.config().MaxMsgs, cfg.MaxMsgs)
			}
			checkPending(pending, pendingBytes)

			// Update msgs to lower.
			cfg = *c.mconfig
			cfg.MaxMsgs = int64(pending / 2)
			if err := mset.update(&cfg); err != nil {
				t.Fatalf("Unexpected error %v", err)
			}
			if mset.config().MaxMsgs != cfg.MaxMsgs {
				t.Fatalf("Expected the change to take effect, %d vs %d", mset.config().MaxMsgs, cfg.MaxMsgs)
			}
			checkPending(pending/2, pendingBytes/2)
			// Now do bytes.
			cfg = *c.mconfig
			cfg.MaxBytes = int64(pendingBytes / 4)
			if err := mset.update(&cfg); err != nil {
				t.Fatalf("Unexpected error %v", err)
			}
			if mset.config().MaxBytes != cfg.MaxBytes {
				t.Fatalf("Expected the change to take effect, %d vs %d", mset.config().MaxBytes, cfg.MaxBytes)
			}
			checkPending(pending/4, pendingBytes/4)

			// Now do age.
			cfg = *c.mconfig
			cfg.MaxAge = time.Second
			if err := mset.update(&cfg); err != nil {
				t.Fatalf("Unexpected error %v", err)
			}
			// Just wait a bit for expiration.
			time.Sleep(2 * time.Second)
			if mset.config().MaxAge != cfg.MaxAge {
				t.Fatalf("Expected the change to take effect, %d vs %d", mset.config().MaxAge, cfg.MaxAge)
			}
			checkPending(0, 0)

			// Now put back to original.
			cfg = *c.mconfig
			if err := mset.update(&cfg); err != nil {
				t.Fatalf("Unexpected error %v", err)
			}
			for i := uint64(0); i < pending; i++ {
				sendStreamMsg(t, nc, "foo", "0123456789")
			}

			// subject changes.
			// Add in a subject first.
			cfg = *c.mconfig
			cfg.Subjects = []string{"foo", "bar"}
			if err := mset.update(&cfg); err != nil {
				t.Fatalf("Unexpected error %v", err)
			}
			// Make sure we can still send to foo.
			sendStreamMsg(t, nc, "foo", "0123456789")
			// And we can now send to bar.
			sendStreamMsg(t, nc, "bar", "0123456789")
			// Now delete both and change to baz only.
			cfg.Subjects = []string{"baz"}
			if err := mset.update(&cfg); err != nil {
				t.Fatalf("Unexpected error %v", err)
			}
			// Make sure we do not get response acks for "foo" or "bar".
			if resp, err := nc.Request("foo", nil, 25*time.Millisecond); err == nil || resp != nil {
				t.Fatalf("Expected no response from jetstream for deleted subject: %q", "foo")
			}
			if resp, err := nc.Request("bar", nil, 25*time.Millisecond); err == nil || resp != nil {
				t.Fatalf("Expected no response from jetstream for deleted subject: %q", "bar")
			}
			// Make sure we can send to "baz"
			sendStreamMsg(t, nc, "baz", "0123456789")
			if nmsgs := mset.state().Msgs; nmsgs != pending+3 {
				t.Fatalf("Expected %d msgs, got %d", pending+3, nmsgs)
			}

			// FileStore restarts for config save.
			cfg = *c.mconfig
			if cfg.Storage == FileStorage {
				cfg.Subjects = []string{"foo", "bar"}
				cfg.MaxMsgs = 2222
				cfg.MaxBytes = 3333333
				cfg.MaxAge = 22 * time.Hour
				if err := mset.update(&cfg); err != nil {
					t.Fatalf("Unexpected error %v", err)
				}
				// Pull since certain defaults etc are set in processing.
				cfg = mset.config()

				// Restart the
				// Capture port since it was dynamic.
				u, _ := url.Parse(s.ClientURL())
				port, _ := strconv.Atoi(u.Port())

				// Stop current
				sd := s.JetStreamConfig().StoreDir
				s.Shutdown()
				// Restart.
				s = RunJetStreamServerOnPort(port, sd)
				defer s.Shutdown()

				mset, err = s.GlobalAccount().lookupStream(cfg.Name)
				if err != nil {
					t.Fatalf("Expected to find a stream for %q", cfg.Name)
				}
				restored_cfg := mset.config()
				if !reflect.DeepEqual(cfg, restored_cfg) {
					t.Fatalf("restored configuration does not match: \n%+v\n vs \n%+v", restored_cfg, cfg)
				}
			}
		})
	}
}

func TestJetStreamDeleteMsg(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{name: "MemoryStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   MemoryStorage,
				Replicas:  1,
			}},
		{name: "FileStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   FileStorage,
				Replicas:  1,
			}},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {

			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			pubTen := func() {
				t.Helper()
				for i := 0; i < 10; i++ {
					js.Publish("foo", []byte("Hello World!"))
				}
			}

			pubTen()

			state := mset.state()
			if state.Msgs != 10 {
				t.Fatalf("Expected 10 messages, got %d", state.Msgs)
			}
			bytesPerMsg := state.Bytes / 10
			if bytesPerMsg == 0 {
				t.Fatalf("Expected non-zero bytes for msg size")
			}

			deleteAndCheck := func(seq, expectedFirstSeq uint64) {
				t.Helper()
				beforeState := mset.state()
				if removed, _ := mset.deleteMsg(seq); !removed {
					t.Fatalf("Expected the delete of sequence %d to succeed", seq)
				}
				expectedState := beforeState
				expectedState.Msgs--
				expectedState.Bytes -= bytesPerMsg
				expectedState.FirstSeq = expectedFirstSeq

				sm, err := mset.getMsg(expectedFirstSeq)
				if err != nil {
					t.Fatalf("Error fetching message for seq: %d - %v", expectedFirstSeq, err)
				}
				expectedState.FirstTime = sm.Time
				expectedState.Deleted = nil
				expectedState.NumDeleted = 0

				afterState := mset.state()
				afterState.Deleted = nil
				afterState.NumDeleted = 0

				// Ignore first time in this test.
				if !reflect.DeepEqual(afterState, expectedState) {
					t.Fatalf("Stats not what we expected. Expected %+v, got %+v\n", expectedState, afterState)
				}
			}

			// Delete one from the middle
			deleteAndCheck(5, 1)
			// Now make sure sequences are updated properly.
			// Delete first msg.
			deleteAndCheck(1, 2)
			// Now last
			deleteAndCheck(10, 2)
			// Now gaps.
			deleteAndCheck(3, 2)
			deleteAndCheck(2, 4)

			mset.purge(nil)
			// Put ten more one.
			pubTen()
			deleteAndCheck(11, 12)
			deleteAndCheck(15, 12)
			deleteAndCheck(16, 12)
			deleteAndCheck(20, 12)

			// Only file storage beyond here.
			if c.mconfig.Storage == MemoryStorage {
				return
			}

			// Capture port since it was dynamic.
			u, _ := url.Parse(s.ClientURL())
			port, _ := strconv.Atoi(u.Port())
			sd := s.JetStreamConfig().StoreDir

			// Shutdown the
			s.Shutdown()

			s = RunJetStreamServerOnPort(port, sd)
			defer s.Shutdown()

			mset, err = s.GlobalAccount().lookupStream("foo")
			if err != nil {
				t.Fatalf("Expected to get the stream back")
			}

			expected := StreamState{Msgs: 6, Bytes: 6 * bytesPerMsg, FirstSeq: 12, LastSeq: 20, NumSubjects: 1}
			state = mset.state()
			state.FirstTime, state.LastTime, state.Deleted, state.NumDeleted = time.Time{}, time.Time{}, nil, 0

			if !reflect.DeepEqual(expected, state) {
				t.Fatalf("State not what we expected. Expected %+v, got %+v\n", expected, state)
			}

			// Now create an consumer and make sure we get the right sequence.
			nc = clientConnectToServer(t, s)
			defer nc.Close()

			delivery := nats.NewInbox()
			sub, _ := nc.SubscribeSync(delivery)
			nc.Flush()

			o, err := mset.addConsumer(&ConsumerConfig{DeliverSubject: delivery, FilterSubject: "foo"})
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}

			expectedStoreSeq := []uint64{12, 13, 14, 17, 18, 19}

			for i := 0; i < 6; i++ {
				m, err := sub.NextMsg(time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				if o.streamSeqFromReply(m.Reply) != expectedStoreSeq[i] {
					t.Fatalf("Expected store seq of %d, got %d", expectedStoreSeq[i], o.streamSeqFromReply(m.Reply))
				}
			}
		})
	}
}

// https://github.com/nats-io/jetstream/issues/396
func TestJetStreamLimitLockBug(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{name: "MemoryStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxMsgs:   10,
				Storage:   MemoryStorage,
				Replicas:  1,
			}},
		{name: "FileStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxMsgs:   10,
				Storage:   FileStorage,
				Replicas:  1,
			}},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {

			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			for i := 0; i < 100; i++ {
				sendStreamMsg(t, nc, "foo", "ok")
			}

			state := mset.state()
			if state.Msgs != 10 {
				t.Fatalf("Expected 10 messages, got %d", state.Msgs)
			}
		})
	}
}

func TestJetStreamNextMsgNoInterest(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{name: "MemoryStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   MemoryStorage,
				Replicas:  1,
			}},
		{name: "FileStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   FileStorage,
				Replicas:  1,
			}},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			cfg := &StreamConfig{Name: "foo", Storage: FileStorage}
			mset, err := s.GlobalAccount().addStream(cfg)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}

			nc := clientConnectWithOldRequest(t, s)
			defer nc.Close()

			// Now create an consumer and make sure it functions properly.
			o, err := mset.addConsumer(workerModeConfig("WQ"))
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			nextSubj := o.requestNextMsgSubject()

			// Queue up a worker but use a short time out.
			if _, err := nc.Request(nextSubj, nil, time.Millisecond); err != nats.ErrTimeout {
				t.Fatalf("Expected a timeout error and no response with acks suppressed")
			}
			// Now send a message, the worker from above will still be known but we want to make
			// sure the system detects that so we will do a request for next msg right behind it.
			nc.Publish("foo", []byte("OK"))
			if msg, err := nc.Request(nextSubj, nil, 5*time.Millisecond); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			} else {
				msg.Respond(nil) // Ack
			}
			// Now queue up 10 workers.
			for i := 0; i < 10; i++ {
				if _, err := nc.Request(nextSubj, nil, time.Microsecond); err != nats.ErrTimeout {
					t.Fatalf("Expected a timeout error and no response with acks suppressed")
				}
			}
			// Now publish ten messages.
			for i := 0; i < 10; i++ {
				nc.Publish("foo", []byte("OK"))
			}
			nc.Flush()
			for i := 0; i < 10; i++ {
				if msg, err := nc.Request(nextSubj, nil, 10*time.Millisecond); err != nil {
					t.Fatalf("Unexpected error for %d: %v", i, err)
				} else {
					msg.Respond(nil) // Ack
				}
			}
			nc.Flush()

			checkFor(t, time.Second, 10*time.Millisecond, func() error {
				ostate := o.info()
				if ostate.AckFloor.Stream != 11 || ostate.NumAckPending > 0 {
					return fmt.Errorf("Inconsistent ack state: %+v", ostate)
				}
				return nil
			})
		})
	}
}

func TestJetStreamMsgHeaders(t *testing.T) {
	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{name: "MemoryStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   MemoryStorage,
				Replicas:  1,
			}},
		{name: "FileStore",
			mconfig: &StreamConfig{
				Name:      "foo",
				Retention: LimitsPolicy,
				MaxAge:    time.Hour,
				Storage:   FileStorage,
				Replicas:  1,
			}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			nc := clientConnectToServer(t, s)
			defer nc.Close()

			m := nats.NewMsg("foo")
			m.Header.Add("Accept-Encoding", "json")
			m.Header.Add("Authorization", "s3cr3t")
			m.Data = []byte("Hello JetStream Headers - #1!")

			nc.PublishMsg(m)
			nc.Flush()

			checkFor(t, time.Second*2, time.Millisecond*250, func() error {
				state := mset.state()
				if state.Msgs != 1 {
					return fmt.Errorf("Expected 1 message, got %d", state.Msgs)
				}
				if state.Bytes == 0 {
					return fmt.Errorf("Expected non-zero bytes")
				}
				return nil
			})

			// Now access raw from stream.
			sm, err := mset.getMsg(1)
			if err != nil {
				t.Fatalf("Unexpected error getting stored message: %v", err)
			}
			// Calculate the []byte version of the headers.
			var b bytes.Buffer
			b.WriteString("NATS/1.0\r\n")
			http.Header(m.Header).Write(&b)
			b.WriteString("\r\n")
			hdr := b.Bytes()

			if !bytes.Equal(sm.Header, hdr) {
				t.Fatalf("Message headers do not match, %q vs %q", hdr, sm.Header)
			}
			if !bytes.Equal(sm.Data, m.Data) {
				t.Fatalf("Message data do not match, %q vs %q", m.Data, sm.Data)
			}

			// Now do consumer based.
			sub, _ := nc.SubscribeSync(nats.NewInbox())
			defer sub.Unsubscribe()
			nc.Flush()

			o, err := mset.addConsumer(&ConsumerConfig{DeliverSubject: sub.Subject})
			if err != nil {
				t.Fatalf("Expected no error with registered interest, got %v", err)
			}
			defer o.delete()

			cm, err := sub.NextMsg(time.Second)
			if err != nil {
				t.Fatalf("Error getting message: %v", err)
			}
			// Check the message.
			// Check out original headers.
			if cm.Header.Get("Accept-Encoding") != "json" ||
				cm.Header.Get("Authorization") != "s3cr3t" {
				t.Fatalf("Original headers not present")
			}
			if !bytes.Equal(m.Data, cm.Data) {
				t.Fatalf("Message payloads are not the same: %q vs %q", cm.Data, m.Data)
			}
		})
	}
}

func TestJetStreamTemplateBasics(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()

	mcfg := &StreamConfig{
		Subjects:  []string{"kv.*"},
		Retention: LimitsPolicy,
		MaxAge:    time.Hour,
		MaxMsgs:   4,
		Storage:   MemoryStorage,
		Replicas:  1,
	}
	template := &StreamTemplateConfig{
		Name:       "kv",
		Config:     mcfg,
		MaxStreams: 4,
	}

	if _, err := acc.addStreamTemplate(template); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if templates := acc.templates(); len(templates) != 1 {
		t.Fatalf("Expected to get array of 1 template, got %d", len(templates))
	}
	if err := acc.deleteStreamTemplate("foo"); err == nil {
		t.Fatalf("Expected an error for non-existent template")
	}
	if err := acc.deleteStreamTemplate(template.Name); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if templates := acc.templates(); len(templates) != 0 {
		t.Fatalf("Expected to get array of no templates, got %d", len(templates))
	}
	// Add it back in and test basics
	if _, err := acc.addStreamTemplate(template); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// Connect a client and send a message which should trigger the stream creation.
	nc := clientConnectToServer(t, s)
	defer nc.Close()

	sendStreamMsg(t, nc, "kv.22", "derek")
	sendStreamMsg(t, nc, "kv.33", "cat")
	sendStreamMsg(t, nc, "kv.44", "sam")
	sendStreamMsg(t, nc, "kv.55", "meg")

	if nms := acc.numStreams(); nms != 4 {
		t.Fatalf("Expected 4 auto-created streams, got %d", nms)
	}

	// This one should fail due to max.
	if resp, err := nc.Request("kv.99", nil, 100*time.Millisecond); err == nil {
		t.Fatalf("Expected this to fail, but got %q", resp.Data)
	}

	// Now delete template and make sure the underlying streams go away too.
	if err := acc.deleteStreamTemplate(template.Name); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	if nms := acc.numStreams(); nms != 0 {
		t.Fatalf("Expected no auto-created streams to remain, got %d", nms)
	}
}

func TestJetStreamTemplateFileStoreRecovery(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()

	mcfg := &StreamConfig{
		Subjects:  []string{"kv.*"},
		Retention: LimitsPolicy,
		MaxAge:    time.Hour,
		MaxMsgs:   50,
		Storage:   FileStorage,
		Replicas:  1,
	}
	template := &StreamTemplateConfig{
		Name:       "kv",
		Config:     mcfg,
		MaxStreams: 100,
	}

	if _, err := acc.addStreamTemplate(template); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// Make sure we can not add in a stream on our own with a template owner.
	badCfg := *mcfg
	badCfg.Name = "bad"
	badCfg.Template = "kv"
	if _, err := acc.addStream(&badCfg); err == nil {
		t.Fatalf("Expected error adding stream with direct template owner")
	}

	// Connect a client and send a message which should trigger the stream creation.
	nc := clientConnectToServer(t, s)
	defer nc.Close()

	for i := 1; i <= 100; i++ {
		subj := fmt.Sprintf("kv.%d", i)
		for x := 0; x < 50; x++ {
			sendStreamMsg(t, nc, subj, "Hello")
		}
	}
	nc.Flush()

	if nms := acc.numStreams(); nms != 100 {
		t.Fatalf("Expected 100 auto-created streams, got %d", nms)
	}

	// Capture port since it was dynamic.
	u, _ := url.Parse(s.ClientURL())
	port, _ := strconv.Atoi(u.Port())

	restartServer := func() {
		t.Helper()
		sd := s.JetStreamConfig().StoreDir
		// Stop current
		s.Shutdown()
		// Restart.
		s = RunJetStreamServerOnPort(port, sd)
	}

	// Restart.
	restartServer()
	defer s.Shutdown()

	acc = s.GlobalAccount()
	if nms := acc.numStreams(); nms != 100 {
		t.Fatalf("Expected 100 auto-created streams, got %d", nms)
	}
	tmpl, err := acc.lookupStreamTemplate(template.Name)
	require_NoError(t, err)
	// Make sure t.delete() survives restart.
	tmpl.delete()

	// Restart.
	restartServer()
	defer s.Shutdown()

	acc = s.GlobalAccount()
	if nms := acc.numStreams(); nms != 0 {
		t.Fatalf("Expected no auto-created streams, got %d", nms)
	}
	if _, err := acc.lookupStreamTemplate(template.Name); err == nil {
		t.Fatalf("Expected to not find the template after restart")
	}
}

// This will be testing our ability to conditionally rewrite subjects for last mile
// when working with JetStream. Consumers receive messages that have their subjects
// rewritten to match the original subject. NATS routing is all subject based except
// for the last mile to the client.
func TestJetStreamSingleInstanceRemoteAccess(t *testing.T) {
	ca := createClusterWithName(t, "A", 1)
	defer shutdownCluster(ca)
	cb := createClusterWithName(t, "B", 1, ca)
	defer shutdownCluster(cb)

	// Connect our leafnode server to cluster B.
	opts := cb.opts[rand.Intn(len(cb.opts))]
	s, _ := runSolicitLeafServer(opts)
	defer s.Shutdown()

	checkLeafNodeConnected(t, s)

	if err := s.EnableJetStream(&JetStreamConfig{StoreDir: t.TempDir()}); err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}

	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: "foo", Storage: MemoryStorage})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	toSend := 10
	for i := 0; i < toSend; i++ {
		sendStreamMsg(t, nc, "foo", "Hello World!")
	}

	// Now create a push based consumer. Connected to the non-jetstream server via a random server on cluster A.
	sl := ca.servers[rand.Intn(len(ca.servers))]
	nc2 := clientConnectToServer(t, sl)
	defer nc2.Close()

	sub, _ := nc2.SubscribeSync(nats.NewInbox())
	defer sub.Unsubscribe()

	// Need to wait for interest to propagate across GW.
	nc2.Flush()
	time.Sleep(25 * time.Millisecond)

	o, err := mset.addConsumer(&ConsumerConfig{DeliverSubject: sub.Subject})
	if err != nil {
		t.Fatalf("Expected no error with registered interest, got %v", err)
	}
	defer o.delete()

	checkSubPending := func(numExpected int) {
		t.Helper()
		checkFor(t, 200*time.Millisecond, 10*time.Millisecond, func() error {
			if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != numExpected {
				return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, numExpected)
			}
			return nil
		})
	}
	checkSubPending(toSend)

	checkMsg := func(m *nats.Msg, err error, i int) {
		t.Helper()
		if err != nil {
			t.Fatalf("Got an error checking message: %v", err)
		}
		if m.Subject != "foo" {
			t.Fatalf("Expected original subject of %q, but got %q", "foo", m.Subject)
		}
		// Now check that reply subject exists and has a sequence as the last token.
		if seq := o.seqFromReply(m.Reply); seq != uint64(i) {
			t.Fatalf("Expected sequence of %d , got %d", i, seq)
		}
	}

	// Now check the subject to make sure its the original one.
	for i := 1; i <= toSend; i++ {
		m, err := sub.NextMsg(time.Second)
		checkMsg(m, err, i)
	}

	// Now do a pull based consumer.
	o, err = mset.addConsumer(workerModeConfig("p"))
	if err != nil {
		t.Fatalf("Expected no error with registered interest, got %v", err)
	}
	defer o.delete()

	nextMsg := o.requestNextMsgSubject()
	for i := 1; i <= toSend; i++ {
		m, err := nc.Request(nextMsg, nil, time.Second)
		checkMsg(m, err, i)
	}
}

func clientConnectToServerWithUP(t *testing.T, opts *Options, user, pass string) *nats.Conn {
	curl := fmt.Sprintf("nats://%s:%s@%s:%d", user, pass, opts.Host, opts.Port)
	nc, err := nats.Connect(curl, nats.Name("JS-UP-TEST"), nats.ReconnectWait(5*time.Millisecond), nats.MaxReconnects(-1))
	if err != nil {
		t.Fatalf("Failed to create client: %v", err)
	}
	return nc
}

func TestJetStreamCanNotEnableOnSystemAccount(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	sa := s.SystemAccount()
	if err := sa.EnableJetStream(nil); err == nil {
		t.Fatalf("Expected an error trying to enable on the system account")
	}
}

func TestJetStreamMultipleAccountsBasics(t *testing.T) {
	tdir := t.TempDir()
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q}
		accounts: {
			A: {
				jetstream: enabled
				users: [ {user: ua, password: pwd} ]
			},
			B: {
				jetstream: {max_mem: 1GB, max_store: 1TB, max_streams: 10, max_consumers: 1k}
				users: [ {user: ub, password: pwd} ]
			},
			C: {
				users: [ {user: uc, password: pwd} ]
			},
		}
	`, tdir)))

	s, opts := RunServerWithConfig(conf)
	defer s.Shutdown()

	if !s.JetStreamEnabled() {
		t.Fatalf("Expected JetStream to be enabled")
	}

	nca := clientConnectToServerWithUP(t, opts, "ua", "pwd")
	defer nca.Close()

	ncb := clientConnectToServerWithUP(t, opts, "ub", "pwd")
	defer ncb.Close()

	resp, err := ncb.Request(JSApiAccountInfo, nil, time.Second)
	require_NoError(t, err)
	var info JSApiAccountInfoResponse
	if err := json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	limits := info.Limits
	if limits.MaxStreams != 10 {
		t.Fatalf("Expected 10 for MaxStreams, got %d", limits.MaxStreams)
	}
	if limits.MaxConsumers != 1000 {
		t.Fatalf("Expected MaxConsumers of %d, got %d", 1000, limits.MaxConsumers)
	}
	gb := int64(1024 * 1024 * 1024)
	if limits.MaxMemory != gb {
		t.Fatalf("Expected MaxMemory to be 1GB, got %d", limits.MaxMemory)
	}
	if limits.MaxStore != 1024*gb {
		t.Fatalf("Expected MaxStore to be 1TB, got %d", limits.MaxStore)
	}

	ncc := clientConnectToServerWithUP(t, opts, "uc", "pwd")
	defer ncc.Close()

	expectNotEnabled := func(resp *nats.Msg, err error) {
		t.Helper()
		if err != nil {
			t.Fatalf("Unexpected error requesting enabled status: %v", err)
		}
		if resp == nil {
			t.Fatalf("No response, possible timeout?")
		}
		var iResp JSApiAccountInfoResponse
		if err := json.Unmarshal(resp.Data, &iResp); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if iResp.Error == nil {
			t.Fatalf("Expected an error on not enabled account")
		}
	}

	// Check C is not enabled. We expect a negative response, not a timeout.
	expectNotEnabled(ncc.Request(JSApiAccountInfo, nil, 250*time.Millisecond))

	// Now do simple reload and check that we do the right thing. Testing enable and disable and also change in limits
	newConf := []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q}
		accounts: {
			A: {
				jetstream: disabled
				users: [ {user: ua, password: pwd} ]
			},
			B: {
				jetstream: {max_mem: 32GB, max_store: 512GB, max_streams: 100, max_consumers: 4k}
				users: [ {user: ub, password: pwd} ]
			},
			C: {
				jetstream: {max_mem: 1GB, max_store: 1TB, max_streams: 10, max_consumers: 1k}
				users: [ {user: uc, password: pwd} ]
			},
		}
	`, tdir))
	if err := os.WriteFile(conf, newConf, 0600); err != nil {
		t.Fatalf("Error rewriting server's config file: %v", err)
	}
	if err := s.Reload(); err != nil {
		t.Fatalf("Error on server reload: %v", err)
	}
	expectNotEnabled(nca.Request(JSApiAccountInfo, nil, 250*time.Millisecond))

	resp, _ = ncb.Request(JSApiAccountInfo, nil, 250*time.Millisecond)
	if err := json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if info.Error != nil {
		t.Fatalf("Expected JetStream to be enabled, got %+v", info.Error)
	}

	resp, _ = ncc.Request(JSApiAccountInfo, nil, 250*time.Millisecond)
	if err := json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if info.Error != nil {
		t.Fatalf("Expected JetStream to be enabled, got %+v", info.Error)
	}

	// Now check that limits have been updated.
	// Account B
	resp, err = ncb.Request(JSApiAccountInfo, nil, time.Second)
	require_NoError(t, err)
	if err := json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	limits = info.Limits
	if limits.MaxStreams != 100 {
		t.Fatalf("Expected 100 for MaxStreams, got %d", limits.MaxStreams)
	}
	if limits.MaxConsumers != 4000 {
		t.Fatalf("Expected MaxConsumers of %d, got %d", 4000, limits.MaxConsumers)
	}
	if limits.MaxMemory != 32*gb {
		t.Fatalf("Expected MaxMemory to be 32GB, got %d", limits.MaxMemory)
	}
	if limits.MaxStore != 512*gb {
		t.Fatalf("Expected MaxStore to be 512GB, got %d", limits.MaxStore)
	}

	// Account C
	resp, err = ncc.Request(JSApiAccountInfo, nil, time.Second)
	require_NoError(t, err)
	if err := json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	limits = info.Limits
	if limits.MaxStreams != 10 {
		t.Fatalf("Expected 10 for MaxStreams, got %d", limits.MaxStreams)
	}
	if limits.MaxConsumers != 1000 {
		t.Fatalf("Expected MaxConsumers of %d, got %d", 1000, limits.MaxConsumers)
	}
	if limits.MaxMemory != gb {
		t.Fatalf("Expected MaxMemory to be 1GB, got %d", limits.MaxMemory)
	}
	if limits.MaxStore != 1024*gb {
		t.Fatalf("Expected MaxStore to be 1TB, got %d", limits.MaxStore)
	}
}

func TestJetStreamServerResourcesConfig(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 2GB, max_file_store: 1TB, store_dir: %q}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	if !s.JetStreamEnabled() {
		t.Fatalf("Expected JetStream to be enabled")
	}

	gb := int64(1024 * 1024 * 1024)
	jsc := s.JetStreamConfig()
	if jsc.MaxMemory != 2*gb {
		t.Fatalf("Expected MaxMemory to be %d, got %d", 2*gb, jsc.MaxMemory)
	}
	if jsc.MaxStore != 1024*gb {
		t.Fatalf("Expected MaxStore to be %d, got %d", 1024*gb, jsc.MaxStore)
	}
}

// From 2.2.2 to 2.2.3 we fixed a bug that would not consistently place a jetstream directory
// under the store directory configured. However there were some cases where the directory was
// created that way and therefore 2.2.3 would start and not recognize the existing accounts,
// streams and consumers.
func TestJetStreamStoreDirectoryFix(t *testing.T) {
	sd := filepath.Join(os.TempDir(), "sd_test")
	defer removeDir(t, sd)

	conf := createConfFile(t, []byte(fmt.Sprintf("listen: 127.0.0.1:-1\njetstream: {store_dir: %q}\n", sd)))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST"}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if _, err := js.Publish("TEST", []byte("TSS")); err != nil {
		t.Fatalf("Unexpected publish error: %v", err)
	}
	// Push based.
	sub, err := js.SubscribeSync("TEST", nats.Durable("dlc"))
	require_NoError(t, err)
	defer sub.Unsubscribe()

	// Now shutdown the server.
	nc.Close()
	s.Shutdown()

	// Now move stuff up from the jetstream directory etc.
	jssd := filepath.Join(sd, JetStreamStoreDir)
	fis, _ := os.ReadDir(jssd)
	// This will be accounts, move them up one directory.
	for _, fi := range fis {
		os.Rename(filepath.Join(jssd, fi.Name()), filepath.Join(sd, fi.Name()))
	}
	removeDir(t, jssd)

	// Restart our server. Make sure our assets got moved.
	s, _ = RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	var names []string
	for name := range js.StreamNames() {
		names = append(names, name)
	}
	if len(names) != 1 {
		t.Fatalf("Expected only 1 stream but got %d", len(names))
	}
	names = names[:0]
	for name := range js.ConsumerNames("TEST") {
		names = append(names, name)
	}
	if len(names) != 1 {
		t.Fatalf("Expected only 1 consumer but got %d", len(names))
	}
}

func TestJetStreamPushConsumersPullError(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST"}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if _, err := js.Publish("TEST", []byte("TSS")); err != nil {
		t.Fatalf("Unexpected publish error: %v", err)
	}
	// Push based.
	sub, err := js.SubscribeSync("TEST")
	require_NoError(t, err)
	defer sub.Unsubscribe()
	ci, err := sub.ConsumerInfo()
	require_NoError(t, err)

	// Now do a pull. Make sure we get an error.
	m, err := nc.Request(fmt.Sprintf(JSApiRequestNextT, "TEST", ci.Name), nil, time.Second)
	require_NoError(t, err)
	if m.Header.Get("Status") != "409" {
		t.Fatalf("Expected a 409 status code, got %q", m.Header.Get("Status"))
	}
}

func TestJetStreamChangeConsumerType(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "TEST", Subjects: []string{"test.*"}})
	require_NoError(t, err)

	// create pull consumer
	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{
		Name:      "pull",
		AckPolicy: nats.AckExplicitPolicy,
	})
	require_NoError(t, err)

	// cannot update pull -> push
	_, err = js.UpdateConsumer("TEST", &nats.ConsumerConfig{
		Name:           "pull",
		AckPolicy:      nats.AckExplicitPolicy,
		DeliverSubject: "foo",
	})
	require_Contains(t, err.Error(), "can not update pull consumer to push based")

	// create push consumer
	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{
		Name:           "push",
		AckPolicy:      nats.AckExplicitPolicy,
		DeliverSubject: "foo",
	})
	require_NoError(t, err)

	// cannot change push -> pull
	_, err = js.UpdateConsumer("TEST", &nats.ConsumerConfig{
		Name:      "push",
		AckPolicy: nats.AckExplicitPolicy,
	})
	require_Contains(t, err.Error(), "can not update push consumer to pull based")
}

////////////////////////////////////////
// Benchmark placeholders
// TODO(dlc) - move
////////////////////////////////////////

func TestJetStreamPubPerf(t *testing.T) {
	// Comment out to run, holding place for now.
	t.SkipNow()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()

	msetConfig := StreamConfig{
		Name:     "sr22",
		Storage:  FileStorage,
		Subjects: []string{"foo"},
	}

	if _, err := acc.addStream(&msetConfig); err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	toSend := 5_000_000
	numProducers := 5

	payload := []byte("Hello World")

	startCh := make(chan bool)
	var wg sync.WaitGroup

	for n := 0; n < numProducers; n++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			<-startCh
			for i := 0; i < int(toSend)/numProducers; i++ {
				nc.Publish("foo", payload)
			}
			nc.Flush()
		}()
	}

	// Wait for Go routines.
	time.Sleep(20 * time.Millisecond)
	start := time.Now()
	close(startCh)
	wg.Wait()

	tt := time.Since(start)
	fmt.Printf("time is %v\n", tt)
	fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds())

	// Stop current
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	// Restart.
	start = time.Now()
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()
	fmt.Printf("Took %v to restart!\n", time.Since(start))
}

func TestJetStreamPubWithAsyncResponsePerf(t *testing.T) {
	// Comment out to run, holding place for now.
	t.SkipNow()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()

	msetConfig := StreamConfig{
		Name:     "sr33",
		Storage:  FileStorage,
		Subjects: []string{"foo"},
	}

	if _, err := acc.addStream(&msetConfig); err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	toSend := 1_000_000
	payload := []byte("Hello World")

	start := time.Now()
	for i := 0; i < toSend; i++ {
		nc.PublishRequest("foo", "bar", payload)
	}
	nc.Flush()

	tt := time.Since(start)
	fmt.Printf("time is %v\n", tt)
	fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds())
}

func TestJetStreamPubWithSyncPerf(t *testing.T) {
	// Comment out to run, holding place for now.
	t.SkipNow()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "foo"})
	require_NoError(t, err)

	toSend := 1_000_000
	payload := []byte("Hello World")

	start := time.Now()
	for i := 0; i < toSend; i++ {
		js.Publish("foo", payload)
	}

	tt := time.Since(start)
	fmt.Printf("time is %v\n", tt)
	fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds())
}

func TestJetStreamPubSubPerf(t *testing.T) {
	// Comment out to run, holding place for now.
	t.SkipNow()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.GlobalAccount()

	msetConfig := StreamConfig{
		Name:     "MSET22",
		Storage:  FileStorage,
		Subjects: []string{"foo"},
	}

	mset, err := acc.addStream(&msetConfig)
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	var toSend = 1_000_000
	var received int
	done := make(chan bool)

	delivery := "d"

	nc.Subscribe(delivery, func(m *nats.Msg) {
		received++
		if received >= toSend {
			done <- true
		}
	})
	nc.Flush()

	_, err = mset.addConsumer(&ConsumerConfig{
		DeliverSubject: delivery,
		AckPolicy:      AckNone,
	})
	if err != nil {
		t.Fatalf("Error creating consumer: %v", err)
	}

	payload := []byte("Hello World")

	start := time.Now()

	for i := 0; i < toSend; i++ {
		nc.Publish("foo", payload)
	}

	<-done
	tt := time.Since(start)
	fmt.Printf("time is %v\n", tt)
	fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds())
}

func TestJetStreamAckExplicitMsgRemoval(t *testing.T) {
	const burstSize = 20

	for _, storageType := range []StorageType{
		FileStorage,
		MemoryStorage,
	} {
		t.Run(storageType.String(), func(t *testing.T) {
			// Start a server
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			// Create a stream
			cfg := &StreamConfig{
				Name:      "MY_STREAM",
				Storage:   storageType,
				Subjects:  []string{"foo.*"},
				Retention: InterestPolicy,
			}
			mset, err := s.GlobalAccount().addStream(cfg)
			require_NoError(t, err)
			defer mset.delete()

			// Create 2 connections
			nc1 := clientConnectToServer(t, s)
			defer nc1.Close()
			nc2 := clientConnectToServer(t, s)
			defer nc2.Close()

			// Create 2 subscription inboxes (for durable consumers DeliverSubject forwarding)
			sub1, err := nc1.SubscribeSync(nats.NewInbox())
			require_NoError(t, err)
			defer sub1.Unsubscribe()
			err = nc1.Flush()
			require_NoError(t, err)

			sub2, err := nc2.SubscribeSync(nats.NewInbox())
			require_NoError(t, err)
			defer sub2.Unsubscribe()
			err = nc2.Flush()
			require_NoError(t, err)

			// Create 2 durable consumers (that forward messages to the inboxes above)
			dc1, err := mset.addConsumer(&ConsumerConfig{
				Durable:        "dur1",
				DeliverSubject: sub1.Subject,
				FilterSubject:  "foo.bar",
				AckPolicy:      AckExplicit,
			})
			require_NoError(t, err)
			defer dc1.delete()

			dc2, err := mset.addConsumer(&ConsumerConfig{
				Durable:        "dur2",
				DeliverSubject: sub2.Subject,
				FilterSubject:  "foo.bar",
				AckPolicy:      AckExplicit,
				AckWait:        100 * time.Millisecond,
			})
			require_NoError(t, err)
			defer dc2.delete()

			// Publish N messages (with subject matching the stream created above)
			for i := 1; i <= burstSize; i++ {
				pubAck := sendStreamMsg(t, nc1, "foo.bar", fmt.Sprintf("msg_%d", i))
				require_Equal(t, int(pubAck.Sequence), i)
			}

			// Check that the stream contains 2 messages
			state := mset.state()
			if state.Msgs != uint64(burstSize) {
				t.Fatalf("Expected %d messages in stream, found %d", burstSize, state.Msgs)
			}

			// Receive and ack both messages from the 2 subscriptions
			for subIndex, sub := range []*nats.Subscription{sub1, sub2} {
				sequences := make(map[uint64]bool, burstSize)

				for i := 1; i <= burstSize; i++ {
					m, err := sub.NextMsg(time.Second)
					require_NoError(t, err)
					err = m.Respond(nil)
					require_NoError(t, err)
					metadata, err := m.Metadata()
					require_NoError(t, err)
					sequences[metadata.Sequence.Stream] = true
				}

				// Verify all known sequence numbers are delivered (as opposed to duplicates)
				for i := uint64(1); i <= burstSize; i++ {
					_, ok := sequences[i]
					if !ok {
						t.Fatalf("Subscriber %d/2 did not deliver message sequence %d", subIndex+1, i)
					}
				}
			}

			// Flush both connections which may have pending ACKs
			err = nc1.Flush()
			require_NoError(t, err)
			err = nc2.Flush()
			require_NoError(t, err)

			// Verify all messages are eventually dropped from the stream (since all known consumers ack'd them)
			checkFor(t, 3*time.Second, 100*time.Millisecond, func() error {
				if state = mset.state(); state.Msgs != 0 {
					return fmt.Errorf("expected empty stream, but found %d messages", state.Msgs)
				}
				return nil
			})

			// Shut down one of the subscriptions
			err = sub2.Unsubscribe()
			require_NoError(t, err)
			err = nc2.Flush()
			require_NoError(t, err)

			// Publish N additional messages
			for i := burstSize + 1; i <= burstSize+burstSize; i++ {
				pubAck := sendStreamMsg(t, nc1, "foo.bar", fmt.Sprintf("msg_%d", i))
				require_Equal(t, i, int(pubAck.Sequence))
			}

			// Check that the stream contains N messages
			state = mset.state()
			if state.Msgs != uint64(burstSize) {
				t.Fatalf("Expected %d messages in stream, found %d", burstSize, state.Msgs)
			}

			// Receive and ack the new messages using the active subscription/consumer
			sequences := make(map[uint64]bool, burstSize)
			for i := 1; i <= burstSize; i++ {
				m, err := sub1.NextMsg(time.Second)
				require_NoError(t, err)
				err = m.Respond(nil)
				require_NoError(t, err)
				metadata, err := m.Metadata()
				require_NoError(t, err)
				sequences[metadata.Sequence.Stream] = true
			}
			// Verify all known sequence numbers are delivered (as opposed to duplicates)
			for i := uint64(burstSize) + 1; i <= burstSize+burstSize; i++ {
				_, ok := sequences[i]
				if !ok {
					t.Fatalf("Subscriber 1/2 did not deliver message sequence %d", i)
				}
			}

			// Create a different subscription inbox
			newSub2, err := nc2.SubscribeSync(nats.NewInbox())
			require_NoError(t, err)
			defer newSub2.Unsubscribe()
			err = nc2.Flush()
			require_NoError(t, err)

			// Update the second durable consumer with the new inbox subscription
			dc2, err = mset.addConsumer(&ConsumerConfig{
				Durable:        "dur2",
				DeliverSubject: newSub2.Subject,
				FilterSubject:  "foo.bar",
				AckPolicy:      AckExplicit,
				AckWait:        100 * time.Millisecond,
			})
			require_NoError(t, err)
			defer dc2.delete()

			// Receive and ack the new messages using the recreated/updated subscription/consumer
			sequences = make(map[uint64]bool, burstSize)
			for i := 1; i <= burstSize; i++ {
				m, err := newSub2.NextMsg(time.Second)
				require_NoError(t, err)
				err = m.Respond(nil)
				require_NoError(t, err)
				metadata, err := m.Metadata()
				require_NoError(t, err)
				sequences[metadata.Sequence.Stream] = true
			}
			// Verify all known sequence numbers are delivered (as opposed to duplicates)
			for i := uint64(burstSize) + 1; i <= burstSize+burstSize; i++ {
				_, ok := sequences[i]
				if !ok {
					t.Fatalf("Subscriber 2/2 did not deliver message sequence %d", i)
				}
			}

			// Flush both connections which may have pending ACKs
			err = nc1.Flush()
			require_NoError(t, err)
			err = nc2.Flush()
			require_NoError(t, err)

			// Verify all messages are eventually dropped from the stream, since all known consumers ack'd them
			checkFor(t, 3*time.Second, 100*time.Millisecond, func() error {
				if state = mset.state(); state.Msgs != 0 {
					return fmt.Errorf("expected empty stream, but found %d messages", state.Msgs)
				}
				return nil
			})
		})
	}
}

func TestJetStreamStoredMsgsDontDisappearAfterCacheExpiration(t *testing.T) {
	sc := &StreamConfig{
		Name:      "MY_STREAM",
		Storage:   FileStorage,
		Subjects:  []string{"foo.>"},
		Retention: InterestPolicy,
	}

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	mset, err := s.GlobalAccount().addStreamWithStore(sc, &FileStoreConfig{BlockSize: 128, CacheExpire: 15 * time.Millisecond})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc1 := clientConnectWithOldRequest(t, s)
	defer nc1.Close()

	// Create a durable consumers
	sub, _ := nc1.SubscribeSync(nats.NewInbox())
	defer sub.Unsubscribe()
	nc1.Flush()

	o, err := mset.addConsumer(&ConsumerConfig{
		Durable:        "dur",
		DeliverSubject: sub.Subject,
		FilterSubject:  "foo.bar",
		DeliverPolicy:  DeliverNew,
		AckPolicy:      AckExplicit,
	})
	if err != nil {
		t.Fatalf("Unexpected error adding consumer: %v", err)
	}
	defer o.delete()

	nc2 := clientConnectWithOldRequest(t, s)
	defer nc2.Close()

	sendStreamMsg(t, nc2, "foo.bar", "msg1")

	msg, err := sub.NextMsg(time.Second)
	if err != nil {
		t.Fatalf("Did not get message: %v", err)
	}
	if string(msg.Data) != "msg1" {
		t.Fatalf("Unexpected message: %q", msg.Data)
	}

	nc1.Close()

	// Get the message from the stream
	getMsgSeq := func(seq uint64) {
		t.Helper()
		mreq := &JSApiMsgGetRequest{Seq: seq}
		req, err := json.Marshal(mreq)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		smsgj, err := nc2.Request(fmt.Sprintf(JSApiMsgGetT, sc.Name), req, time.Second)
		if err != nil {
			t.Fatalf("Could not retrieve stream message: %v", err)
		}
		if strings.Contains(string(smsgj.Data), "code") {
			t.Fatalf("Error: %q", smsgj.Data)
		}
	}

	getMsgSeq(1)

	time.Sleep(time.Second)

	sendStreamMsg(t, nc2, "foo.bar", "msg2")
	sendStreamMsg(t, nc2, "foo.bar", "msg3")

	getMsgSeq(1)
	getMsgSeq(2)
	getMsgSeq(3)
}

func TestJetStreamDeliveryAfterServerRestart(t *testing.T) {
	opts := DefaultTestOptions
	opts.Port = -1
	opts.JetStream = true
	opts.StoreDir = t.TempDir()
	s := RunServer(&opts)
	defer s.Shutdown()

	mset, err := s.GlobalAccount().addStream(&StreamConfig{
		Name:      "MY_STREAM",
		Storage:   FileStorage,
		Subjects:  []string{"foo.>"},
		Retention: InterestPolicy,
	})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	inbox := nats.NewInbox()
	o, err := mset.addConsumer(&ConsumerConfig{
		Durable:        "dur",
		DeliverSubject: inbox,
		DeliverPolicy:  DeliverNew,
		AckPolicy:      AckExplicit,
	})
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	defer o.delete()

	sub, err := nc.SubscribeSync(inbox)
	if err != nil {
		t.Fatalf("Error on subscribe: %v", err)
	}
	nc.Flush()

	// Send 1 message
	sendStreamMsg(t, nc, "foo.bar", "msg1")

	// Make sure we receive it and ack it.
	msg, err := sub.NextMsg(250 * time.Millisecond)
	if err != nil {
		t.Fatalf("Did not get message: %v", err)
	}
	// Ack it!
	msg.Respond(nil)
	nc.Flush()

	// Shutdown client and server
	nc.Close()

	dir := strings.TrimSuffix(s.JetStreamConfig().StoreDir, JetStreamStoreDir)
	s.Shutdown()

	opts.Port = -1
	opts.StoreDir = dir
	s = RunServer(&opts)
	defer s.Shutdown()

	// Lookup stream.
	mset, err = s.GlobalAccount().lookupStream("MY_STREAM")
	if err != nil {
		t.Fatalf("Error looking up stream: %v", err)
	}

	// Update consumer's deliver subject with new inbox
	inbox = nats.NewInbox()
	o, err = mset.addConsumer(&ConsumerConfig{
		Durable:        "dur",
		DeliverSubject: inbox,
		DeliverPolicy:  DeliverNew,
		AckPolicy:      AckExplicit,
	})
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	defer o.delete()

	nc = clientConnectToServer(t, s)
	defer nc.Close()

	// Send 2nd message
	sendStreamMsg(t, nc, "foo.bar", "msg2")

	// Start sub on new inbox
	sub, err = nc.SubscribeSync(inbox)
	if err != nil {
		t.Fatalf("Error on subscribe: %v", err)
	}
	nc.Flush()

	// Should receive message 2.
	if _, err := sub.NextMsg(500 * time.Millisecond); err != nil {
		t.Fatalf("Did not get message: %v", err)
	}
}

// This is for the basics of importing the ability to send to a stream and consume
// from a consumer that is pull based on push based on a well known delivery subject.
func TestJetStreamAccountImportBasics(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		no_auth_user: rip
		jetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q}
		accounts: {
			JS: {
				jetstream: enabled
				users: [ {user: dlc, password: foo} ]
				exports [
					# This is for sending into a stream from other accounts.
					{ service: "ORDERS.*" }
					# This is for accessing a pull based consumer.
					{ service: "$JS.API.CONSUMER.MSG.NEXT.*.*" }
					# This is streaming to a delivery subject for a push based consumer.
					{ stream: "deliver.ORDERS" }
					# This is to ack received messages. This is a service to ack acks..
					{ service: "$JS.ACK.ORDERS.*.>" }
				]
			},
			IU: {
				users: [ {user: rip, password: bar} ]
				imports [
					{ service: { subject: "ORDERS.*", account: JS }, to: "my.orders.$1" }
					{ service: { subject: "$JS.API.CONSUMER.MSG.NEXT.ORDERS.d", account: JS }, to: "nxt.msg" }
					{ stream:  { subject: "deliver.ORDERS", account: JS }, to: "d" }
					{ service: { subject: "$JS.ACK.ORDERS.*.>", account: JS } }
				]
			},
		}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	acc, err := s.LookupAccount("JS")
	if err != nil {
		t.Fatalf("Unexpected error looking up account: %v", err)
	}

	mset, err := acc.addStream(&StreamConfig{Name: "ORDERS", Subjects: []string{"ORDERS.*"}})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	// This should be the rip user, the one that imports some JS.
	nc := clientConnectToServer(t, s)
	defer nc.Close()

	// Simple publish to a stream.
	pubAck := sendStreamMsg(t, nc, "my.orders.foo", "ORDERS-1")
	if pubAck.Stream != "ORDERS" || pubAck.Sequence != 1 {
		t.Fatalf("Bad pubAck received: %+v", pubAck)
	}
	if msgs := mset.state().Msgs; msgs != 1 {
		t.Fatalf("Expected 1 message, got %d", msgs)
	}

	total := 2
	for i := 2; i <= total; i++ {
		sendStreamMsg(t, nc, "my.orders.bar", fmt.Sprintf("ORDERS-%d", i))
	}
	if msgs := mset.state().Msgs; msgs != uint64(total) {
		t.Fatalf("Expected %d messages, got %d", total, msgs)
	}

	// Now test access to a pull based consumer, e.g. workqueue.
	o, err := mset.addConsumer(&ConsumerConfig{
		Durable:   "d",
		AckPolicy: AckExplicit,
	})
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	defer o.delete()

	// We mapped the next message request, "$JS.API.CONSUMER.MSG.NEXT.ORDERS.d" -> "nxt.msg"
	m, err := nc.Request("nxt.msg", nil, time.Second)
	require_NoError(t, err)
	if string(m.Data) != "ORDERS-1" {
		t.Fatalf("Expected to receive %q, got %q", "ORDERS-1", m.Data)
	}

	// Now test access to a push based consumer
	o, err = mset.addConsumer(&ConsumerConfig{
		Durable:        "p",
		DeliverSubject: "deliver.ORDERS",
		AckPolicy:      AckExplicit,
	})
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	defer o.delete()

	// We remapped from above, deliver.ORDERS -> d
	sub, _ := nc.SubscribeSync("d")
	defer sub.Unsubscribe()

	checkFor(t, 250*time.Millisecond, 10*time.Millisecond, func() error {
		if nmsgs, _, _ := sub.Pending(); err != nil || nmsgs != total {
			return fmt.Errorf("Did not receive correct number of messages: %d vs %d", nmsgs, total)
		}
		return nil
	})

	m, _ = sub.NextMsg(time.Second)
	// Make sure we remapped subject correctly across the account boundary.
	if m.Subject != "ORDERS.foo" {
		t.Fatalf("Expected subject of %q, got %q", "ORDERS.foo", m.Subject)
	}
	// Now make sure we can ack messages correctly.
	m.Respond(AckAck)
	nc.Flush()

	if info := o.info(); info.AckFloor.Consumer != 1 {
		t.Fatalf("Did not receive the ack properly")
	}

	// Grab second one now.
	m, _ = sub.NextMsg(time.Second)
	// Make sure we remapped subject correctly across the account boundary.
	if m.Subject != "ORDERS.bar" {
		t.Fatalf("Expected subject of %q, got %q", "ORDERS.bar", m.Subject)
	}
	// Now make sure we can ack messages and get back an ack as well.
	resp, err := nc.Request(m.Reply, nil, 100*time.Millisecond)
	if resp == nil {
		t.Fatalf("No response (error: %v)", err)
	}
	if info := o.info(); info.AckFloor.Consumer != 2 {
		t.Fatalf("Did not receive the ack properly")
	}
}

// This tests whether we are able to aggregate all JetStream advisory events
// from all accounts into a single account. Config for this test uses
// service imports and exports as that allows for gathering all events
// without having to know the account name and without separate entries
// for each account in aggregate account config.
// This test fails as it is not receiving the api audit event ($JS.EVENT.ADVISORY.API).
func TestJetStreamAccountImportJSAdvisoriesAsService(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen=127.0.0.1:-1
		no_auth_user: pp
		jetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q}
		accounts {
			JS {
				jetstream: enabled
				users: [ {user: pp, password: foo} ]
				imports [
					{ service: { account: AGG, subject: '$JS.EVENT.ADVISORY.ACC.JS.>' }, to: '$JS.EVENT.ADVISORY.>' }
				]
			}
			AGG {
				users: [ {user: agg, password: foo} ]
				exports: [
					{ service: '$JS.EVENT.ADVISORY.ACC.*.>', response: Singleton, account_token_position: 5 }
				]
			}
		}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	// This should be the pp user, one which manages JetStream assets
	ncJS, err := nats.Connect(s.ClientURL())
	if err != nil {
		t.Fatalf("Unexpected error during connect: %v", err)
	}
	defer ncJS.Close()

	// This is the agg user, which should aggregate all JS advisory events.
	ncAgg, err := nats.Connect(s.ClientURL(), nats.UserInfo("agg", "foo"))
	if err != nil {
		t.Fatalf("Unexpected error during connect: %v", err)
	}
	defer ncAgg.Close()

	js, err := ncJS.JetStream()
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// user from JS account should receive events on $JS.EVENT.ADVISORY.> subject
	subJS, err := ncJS.SubscribeSync("$JS.EVENT.ADVISORY.>")
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	defer subJS.Unsubscribe()
	require_NoError(t, ncJS.Flush())

	// user from AGG account should receive events on mapped $JS.EVENT.ADVISORY.ACC.JS.> subject (with account name)
	subAgg, err := ncAgg.SubscribeSync("$JS.EVENT.ADVISORY.ACC.JS.>")
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	defer subAgg.Unsubscribe()
	require_NoError(t, ncAgg.Flush())

	// add stream using JS account
	// this should trigger 2 events:
	// - an action event on $JS.EVENT.ADVISORY.STREAM.CREATED.ORDERS
	// - an api audit event on $JS.EVENT.ADVISORY.API
	_, err = js.AddStream(&nats.StreamConfig{Name: "ORDERS", Subjects: []string{"ORDERS.*"}})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	gotEvents := map[string]int{}
	for i := 0; i < 2; i++ {
		msg, err := subJS.NextMsg(time.Second * 2)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		gotEvents[msg.Subject]++
	}
	if c := gotEvents["$JS.EVENT.ADVISORY.STREAM.CREATED.ORDERS"]; c != 1 {
		t.Fatalf("Should have received one advisory from $JS.EVENT.ADVISORY.STREAM.CREATED.ORDERS but got %d", c)
	}
	if c := gotEvents["$JS.EVENT.ADVISORY.API"]; c != 1 {
		t.Fatalf("Should have received one advisory from $JS.EVENT.ADVISORY.API but got %d", c)
	}

	// same set of events should be received by AGG account
	// on subjects containing account name (ACC.JS)
	gotEvents = map[string]int{}
	for i := 0; i < 2; i++ {
		msg, err := subAgg.NextMsg(time.Second * 2)
		require_NoError(t, err)
		var adv JSAPIAudit
		require_NoError(t, json.Unmarshal(msg.Data, &adv))
		// Make sure we have full fidelity info via implicit share.
		if adv.Client != nil {
			require_True(t, adv.Client.Host != _EMPTY_)
			require_True(t, adv.Client.User != _EMPTY_)
			require_True(t, adv.Client.Lang != _EMPTY_)
		}
		gotEvents[msg.Subject]++
	}
	if c := gotEvents["$JS.EVENT.ADVISORY.ACC.JS.STREAM.CREATED.ORDERS"]; c != 1 {
		t.Fatalf("Should have received one advisory from $JS.EVENT.ADVISORY.ACC.JS.STREAM.CREATED.ORDERS but got %d", c)
	}
	if c := gotEvents["$JS.EVENT.ADVISORY.ACC.JS.API"]; c != 1 {
		t.Fatalf("Should have received one advisory from $JS.EVENT.ADVISORY.ACC.JS.API but got %d", c)
	}
}

// This tests whether we are able to aggregate all JetStream advisory events
// from all accounts into a single account. Config for this test uses
// stream imports and exports as that allows for gathering all events
// as long as there is a separate stream import entry for each account
// in aggregate account config.
func TestJetStreamAccountImportJSAdvisoriesAsStream(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen=127.0.0.1:-1
		no_auth_user: pp
		jetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q}
		accounts {
			JS {
				jetstream: enabled
				users: [ {user: pp, password: foo} ]
				exports [
					{ stream: '$JS.EVENT.ADVISORY.>' }
				]
			}
			AGG {
				users: [ {user: agg, password: foo} ]
				imports: [
					{ stream: { account: JS, subject: '$JS.EVENT.ADVISORY.>' }, to: '$JS.EVENT.ADVISORY.ACC.JS.>' }
				]
			}
		}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	// This should be the pp user, one which manages JetStream assets
	ncJS, err := nats.Connect(s.ClientURL())
	if err != nil {
		t.Fatalf("Unexpected error during connect: %v", err)
	}
	defer ncJS.Close()

	// This is the agg user, which should aggregate all JS advisory events.
	ncAgg, err := nats.Connect(s.ClientURL(), nats.UserInfo("agg", "foo"))
	if err != nil {
		t.Fatalf("Unexpected error during connect: %v", err)
	}
	defer ncAgg.Close()

	js, err := ncJS.JetStream()
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// user from JS account should receive events on $JS.EVENT.ADVISORY.> subject
	subJS, err := ncJS.SubscribeSync("$JS.EVENT.ADVISORY.>")
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	defer subJS.Unsubscribe()
	require_NoError(t, ncJS.Flush())

	// user from AGG account should receive events on mapped $JS.EVENT.ADVISORY.ACC.JS.> subject (with account name)
	subAgg, err := ncAgg.SubscribeSync("$JS.EVENT.ADVISORY.ACC.JS.>")
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	defer subAgg.Unsubscribe()
	require_NoError(t, ncAgg.Flush())

	// add stream using JS account
	// this should trigger 2 events:
	// - an action event on $JS.EVENT.ADVISORY.STREAM.CREATED.ORDERS
	// - an api audit event on $JS.EVENT.ADVISORY.API
	_, err = js.AddStream(&nats.StreamConfig{Name: "ORDERS", Subjects: []string{"ORDERS.*"}})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}

	var gotAPIAdvisory, gotCreateAdvisory bool
	for i := 0; i < 2; i++ {
		msg, err := subJS.NextMsg(time.Second * 2)
		if err != nil {
			t.Fatalf("Unexpected error on JS account: %v", err)
		}
		switch msg.Subject {
		case "$JS.EVENT.ADVISORY.STREAM.CREATED.ORDERS":
			gotCreateAdvisory = true
		case "$JS.EVENT.ADVISORY.API":
			gotAPIAdvisory = true
		default:
			t.Fatalf("Unexpected subject: %q", msg.Subject)
		}
	}
	if !gotAPIAdvisory || !gotCreateAdvisory {
		t.Fatalf("Expected to have received both advisories on JS account (API advisory %v, create advisory %v)", gotAPIAdvisory, gotCreateAdvisory)
	}

	// same set of events should be received by AGG account
	// on subjects containing account name (ACC.JS)
	gotAPIAdvisory, gotCreateAdvisory = false, false
	for i := 0; i < 2; i++ {
		msg, err := subAgg.NextMsg(time.Second * 2)
		if err != nil {
			t.Fatalf("Unexpected error on AGG account: %v", err)
		}
		switch msg.Subject {
		case "$JS.EVENT.ADVISORY.ACC.JS.STREAM.CREATED.ORDERS":
			gotCreateAdvisory = true
		case "$JS.EVENT.ADVISORY.ACC.JS.API":
			gotAPIAdvisory = true
		default:
			t.Fatalf("Unexpected subject: %q", msg.Subject)
		}
	}
	if !gotAPIAdvisory || !gotCreateAdvisory {
		t.Fatalf("Expected to have received both advisories on AGG account (API advisory %v, create advisory %v)", gotAPIAdvisory, gotCreateAdvisory)
	}
}

// This is for importing all of JetStream into another account for admin purposes.
func TestJetStreamAccountImportAll(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		no_auth_user: rip
		jetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q}
		accounts: {
			JS: {
				jetstream: enabled
				users: [ {user: dlc, password: foo} ]
				exports [ { service: "$JS.API.>" } ]
			},
			IU: {
				users: [ {user: rip, password: bar} ]
				imports [ { service: { subject: "$JS.API.>", account: JS }, to: "jsapi.>"} ]
			},
		}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	acc, err := s.LookupAccount("JS")
	if err != nil {
		t.Fatalf("Unexpected error looking up account: %v", err)
	}

	mset, err := acc.addStream(&StreamConfig{Name: "ORDERS", Subjects: []string{"ORDERS.*"}})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	// This should be the rip user, the one that imports all of JS.
	nc := clientConnectToServer(t, s)
	defer nc.Close()

	mapSubj := func(subject string) string {
		return strings.Replace(subject, "$JS.API.", "jsapi.", 1)
	}

	// This will get the current information about usage and limits for this account.
	resp, err := nc.Request(mapSubj(JSApiAccountInfo), nil, time.Second)
	require_NoError(t, err)
	var info JSApiAccountInfoResponse
	if err := json.Unmarshal(resp.Data, &info); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if info.Error != nil {
		t.Fatalf("Unexpected error: %+v", info.Error)
	}
	// Lookup streams.
	resp, err = nc.Request(mapSubj(JSApiStreams), nil, time.Second)
	require_NoError(t, err)
	var namesResponse JSApiStreamNamesResponse
	if err = json.Unmarshal(resp.Data, &namesResponse); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if namesResponse.Error != nil {
		t.Fatalf("Unexpected error: %+v", namesResponse.Error)
	}
}

// https://github.com/nats-io/nats-server/issues/1736
func TestJetStreamServerReload(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q }
		accounts: {
			A: { users: [ {user: ua, password: pwd} ] },
			B: {
				jetstream: {max_mem: 1GB, max_store: 1TB, max_streams: 10, max_consumers: 1k}
				users: [ {user: ub, password: pwd} ]
			},
			SYS: { users: [ {user: uc, password: pwd} ] },
		}
		no_auth_user: ub
		system_account: SYS
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	if !s.JetStreamEnabled() {
		t.Fatalf("Expected JetStream to be enabled")
	}

	// Client for API requests.
	nc := clientConnectToServer(t, s)
	defer nc.Close()

	checkJSAccount := func() {
		t.Helper()
		resp, err := nc.Request(JSApiAccountInfo, nil, time.Second)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		var info JSApiAccountInfoResponse
		if err := json.Unmarshal(resp.Data, &info); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
	}

	checkJSAccount()

	acc, err := s.LookupAccount("B")
	if err != nil {
		t.Fatalf("Unexpected error looking up account: %v", err)
	}
	mset, err := acc.addStream(&StreamConfig{Name: "22"})
	require_NoError(t, err)

	toSend := 10
	for i := 0; i < toSend; i++ {
		sendStreamMsg(t, nc, "22", fmt.Sprintf("MSG: %d", i+1))
	}
	if msgs := mset.state().Msgs; msgs != uint64(toSend) {
		t.Fatalf("Expected %d messages, got %d", toSend, msgs)
	}

	if err := s.Reload(); err != nil {
		t.Fatalf("Error on server reload: %v", err)
	}

	// Wait to get reconnected.
	checkFor(t, 5*time.Second, 10*time.Millisecond, func() error {
		if !nc.IsConnected() {
			return fmt.Errorf("Not connected")
		}
		return nil
	})

	checkJSAccount()
	sendStreamMsg(t, nc, "22", "MSG: 22")
}

func TestJetStreamConfigReloadWithGlobalAccount(t *testing.T) {
	tdir := t.TempDir()
	template := `
		listen: 127.0.0.1:-1
		authorization {
			users [
				{user: anonymous}
				{user: user1, password: %s}
			]
		}
		no_auth_user: anonymous
		jetstream {
			store_dir = %q
		}
	`
	conf := createConfFile(t, []byte(fmt.Sprintf(template, "pwd", tdir)))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	checkJSAccount := func() {
		t.Helper()
		if _, err := js.AccountInfo(); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
	}

	checkJSAccount()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "foo"}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	toSend := 10
	for i := 0; i < toSend; i++ {
		if _, err := js.Publish("foo", []byte(fmt.Sprintf("MSG: %d", i+1))); err != nil {
			t.Fatalf("Unexpected publish error: %v", err)
		}
	}
	si, err := js.StreamInfo("foo")
	require_NoError(t, err)
	if si.State.Msgs != uint64(toSend) {
		t.Fatalf("Expected %d msgs after restart, got %d", toSend, si.State.Msgs)
	}

	if err := os.WriteFile(conf, []byte(fmt.Sprintf(template, "pwd2", tdir)), 0666); err != nil {
		t.Fatalf("Error writing config: %v", err)
	}

	if err := s.Reload(); err != nil {
		t.Fatalf("Error during config reload: %v", err)
	}

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	// Try to add a new stream to the global account
	if _, err := js.AddStream(&nats.StreamConfig{Name: "bar"}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	checkJSAccount()
}

// Test that we properly enforce per subject msg limits.
func TestJetStreamMaxMsgsPerSubject(t *testing.T) {
	const maxPer = 5
	msc := StreamConfig{
		Name:       "TEST",
		Subjects:   []string{"foo", "bar", "baz.*"},
		Storage:    MemoryStorage,
		MaxMsgsPer: maxPer,
	}
	fsc := msc
	fsc.Storage = FileStorage

	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &msc},
		{"FileStore", &fsc},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			if err != nil {
				t.Fatalf("Unexpected error adding stream: %v", err)
			}
			defer mset.delete()

			// Client for API requests.
			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			pubAndCheck := func(subj string, num int, expectedNumMsgs uint64) {
				t.Helper()
				for i := 0; i < num; i++ {
					if _, err = js.Publish(subj, []byte("TSLA")); err != nil {
						t.Fatalf("Unexpected publish error: %v", err)
					}
				}
				si, err := js.StreamInfo("TEST")
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				if si.State.Msgs != expectedNumMsgs {
					t.Fatalf("Expected %d msgs, got %d", expectedNumMsgs, si.State.Msgs)
				}
			}

			pubAndCheck("foo", 1, 1)
			pubAndCheck("foo", 4, 5)
			// Now make sure our per subject limits kick in..
			pubAndCheck("foo", 2, 5)
			pubAndCheck("baz.22", 5, 10)
			pubAndCheck("baz.33", 5, 15)
			// We are maxed so totals should be same no matter what we add here.
			pubAndCheck("baz.22", 5, 15)
			pubAndCheck("baz.33", 5, 15)

			// Now purge and make sure all is still good.
			mset.purge(nil)
			pubAndCheck("foo", 1, 1)
			pubAndCheck("foo", 4, 5)
			pubAndCheck("baz.22", 5, 10)
			pubAndCheck("baz.33", 5, 15)
		})
	}
}

func TestJetStreamGetLastMsgBySubject(t *testing.T) {
	for _, st := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(st.String(), func(t *testing.T) {
			c := createJetStreamClusterExplicit(t, "JSC", 3)
			defer c.shutdown()

			nc, js := jsClientConnect(t, c.randomServer())
			defer nc.Close()

			cfg := StreamConfig{
				Name:       "KV",
				Subjects:   []string{"kv.>"},
				Storage:    st,
				Replicas:   2,
				MaxMsgsPer: 20,
			}

			req, err := json.Marshal(cfg)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			// Do manually for now.
			nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
			si, err := js.StreamInfo("KV")
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			if si == nil || si.Config.Name != "KV" {
				t.Fatalf("StreamInfo is not correct %+v", si)
			}

			for i := 0; i < 1000; i++ {
				msg := []byte(fmt.Sprintf("VAL-%d", i+1))
				js.PublishAsync("kv.foo", msg)
				js.PublishAsync("kv.bar", msg)
				js.PublishAsync("kv.baz", msg)
			}
			select {
			case <-js.PublishAsyncComplete():
			case <-time.After(5 * time.Second):
				t.Fatalf("Did not receive completion signal")
			}

			// Check that if both set that errors.
			b, _ := json.Marshal(JSApiMsgGetRequest{LastFor: "kv.foo", Seq: 950})
			rmsg, err := nc.Request(fmt.Sprintf(JSApiMsgGetT, "KV"), b, time.Second)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			var resp JSApiMsgGetResponse
			err = json.Unmarshal(rmsg.Data, &resp)
			if err != nil {
				t.Fatalf("Could not parse stream message: %v", err)
			}
			if resp.Error == nil {
				t.Fatalf("Expected an error when both are set, got %+v", resp.Error)
			}

			// Need to do stream GetMsg by hand for now until Go client support lands.
			getLast := func(subject string) *StoredMsg {
				t.Helper()
				req := &JSApiMsgGetRequest{LastFor: subject}
				b, _ := json.Marshal(req)
				rmsg, err := nc.Request(fmt.Sprintf(JSApiMsgGetT, "KV"), b, time.Second)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				var resp JSApiMsgGetResponse
				err = json.Unmarshal(rmsg.Data, &resp)
				if err != nil {
					t.Fatalf("Could not parse stream message: %v", err)
				}
				if resp.Message == nil || resp.Error != nil {
					t.Fatalf("Did not receive correct response: %+v", resp.Error)
				}
				return resp.Message
			}
			// Do basic checks.
			basicCheck := func(subject string, expectedSeq uint64) {
				sm := getLast(subject)
				if sm == nil {
					t.Fatalf("Expected a message but got none")
				} else if string(sm.Data) != "VAL-1000" {
					t.Fatalf("Wrong message payload, wanted %q but got %q", "VAL-1000", sm.Data)
				} else if sm.Sequence != expectedSeq {
					t.Fatalf("Wrong message sequence, wanted %d but got %d", expectedSeq, sm.Sequence)
				} else if !subjectIsSubsetMatch(sm.Subject, subject) {
					t.Fatalf("Wrong subject, wanted %q but got %q", subject, sm.Subject)
				}
			}

			basicCheck("kv.foo", 2998)
			basicCheck("kv.bar", 2999)
			basicCheck("kv.baz", 3000)
			basicCheck("kv.*", 3000)
			basicCheck(">", 3000)
		})
	}
}

// https://github.com/nats-io/nats-server/issues/2329
func TestJetStreamGetLastMsgBySubjectAfterUpdate(t *testing.T) {
	c := createJetStreamClusterExplicit(t, "JSC", 3)
	defer c.shutdown()

	nc, js := jsClientConnect(t, c.randomServer())
	defer nc.Close()

	sc := &nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
		Replicas: 2,
	}
	if _, err := js.AddStream(sc); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	// Now Update and add in other subjects.
	sc.Subjects = append(sc.Subjects, "bar", "baz")
	if _, err := js.UpdateStream(sc); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	js.Publish("foo", []byte("OK1")) // 1
	js.Publish("bar", []byte("OK1")) // 2
	js.Publish("foo", []byte("OK2")) // 3
	js.Publish("bar", []byte("OK2")) // 4

	// Need to do stream GetMsg by hand for now until Go client support lands.
	getLast := func(subject string) *StoredMsg {
		t.Helper()
		req := &JSApiMsgGetRequest{LastFor: subject}
		b, _ := json.Marshal(req)
		rmsg, err := nc.Request(fmt.Sprintf(JSApiMsgGetT, "TEST"), b, time.Second)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		var resp JSApiMsgGetResponse
		err = json.Unmarshal(rmsg.Data, &resp)
		if err != nil {
			t.Fatalf("Could not parse stream message: %v", err)
		}
		if resp.Message == nil || resp.Error != nil {
			t.Fatalf("Did not receive correct response: %+v", resp.Error)
		}
		return resp.Message
	}
	// Do basic checks.
	basicCheck := func(subject string, expectedSeq uint64) {
		sm := getLast(subject)
		if sm == nil {
			t.Fatalf("Expected a message but got none")
		} else if sm.Sequence != expectedSeq {
			t.Fatalf("Wrong message sequence, wanted %d but got %d", expectedSeq, sm.Sequence)
		} else if !subjectIsSubsetMatch(sm.Subject, subject) {
			t.Fatalf("Wrong subject, wanted %q but got %q", subject, sm.Subject)
		}
	}

	basicCheck("foo", 3)
	basicCheck("bar", 4)
}

func TestJetStreamLastSequenceBySubject(t *testing.T) {
	for _, st := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(st.String(), func(t *testing.T) {
			c := createJetStreamClusterExplicit(t, "JSC", 3)
			defer c.shutdown()

			nc, js := jsClientConnect(t, c.randomServer())
			defer nc.Close()

			cfg := StreamConfig{
				Name:       "KV",
				Subjects:   []string{"kv.>"},
				Storage:    st,
				Replicas:   3,
				MaxMsgsPer: 1,
			}

			req, err := json.Marshal(cfg)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			// Do manually for now.
			m, err := nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
			require_NoError(t, err)
			si, err := js.StreamInfo("KV")
			if err != nil {
				t.Fatalf("Unexpected error: %v, respmsg: %q", err, string(m.Data))
			}
			if si == nil || si.Config.Name != "KV" {
				t.Fatalf("StreamInfo is not correct %+v", si)
			}

			js.PublishAsync("kv.foo", []byte("1"))
			js.PublishAsync("kv.bar", []byte("2"))
			js.PublishAsync("kv.baz", []byte("3"))

			select {
			case <-js.PublishAsyncComplete():
			case <-time.After(time.Second):
				t.Fatalf("Did not receive completion signal")
			}

			// Now make sure we get an error if the last sequence is not correct per subject.
			pubAndCheck := func(subj, seq string, ok bool) {
				t.Helper()
				m := nats.NewMsg(subj)
				m.Data = []byte("HELLO")
				m.Header.Set(JSExpectedLastSubjSeq, seq)
				_, err := js.PublishMsg(m)
				if ok && err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				if !ok && err == nil {
					t.Fatalf("Expected to get an error and got none")
				}
			}

			pubAndCheck("kv.foo", "1", true)  // So last is now 4.
			pubAndCheck("kv.foo", "1", false) // This should fail.
			pubAndCheck("kv.bar", "2", true)
			pubAndCheck("kv.bar", "5", true)
			pubAndCheck("kv.xxx", "5", false)
		})
	}
}

func TestJetStreamLastSequenceBySubjectWithSubject(t *testing.T) {
	test := func(replicas int, st StorageType) {
		t.Run(fmt.Sprintf("R%d/%s", replicas, st), func(t *testing.T) {
			c := createJetStreamClusterExplicit(t, "JSC", 3)
			defer c.shutdown()

			nc, js := jsClientConnect(t, c.randomServer())
			defer nc.Close()

			cfg := StreamConfig{
				Name:       "KV",
				Subjects:   []string{"kv.>"},
				Storage:    st,
				Replicas:   replicas,
				MaxMsgsPer: 1,
			}

			req, err := json.Marshal(cfg)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			// Do manually for now.
			m, err := nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
			require_NoError(t, err)
			si, err := js.StreamInfo("KV")
			if err != nil {
				t.Fatalf("Unexpected error: %v, respmsg: %q", err, string(m.Data))
			}
			if si == nil || si.Config.Name != "KV" {
				t.Fatalf("StreamInfo is not correct %+v", si)
			}

			js.PublishAsync("kv.1.foo", []byte("1:1")) // Last is 1 for kv.1.foo; 1 for kv.1.*;
			js.PublishAsync("kv.1.bar", []byte("1:2")) // Last is 2 for kv.1.bar; 2 for kv.1.*;
			js.PublishAsync("kv.2.foo", []byte("2:1")) // Last is 3 for kv.2.foo; 3 for kv.2.*;
			js.PublishAsync("kv.3.bar", []byte("3:1")) // Last is 4 for kv.3.bar; 4 for kv.3.*;
			js.PublishAsync("kv.1.baz", []byte("1:3")) // Last is 5 for kv.1.baz; 5 for kv.1.*;
			js.PublishAsync("kv.1.bar", []byte("1:4")) // Last is 6 for kv.1.baz; 6 for kv.1.*;
			js.PublishAsync("kv.2.baz", []byte("2:2")) // Last is 7 for kv.2.baz; 7 for kv.2.*;

			select {
			case <-js.PublishAsyncComplete():
			case <-time.After(time.Second):
				t.Fatalf("Did not receive completion signal")
			}

			// Now make sure we get an error if the last sequence is not correct per subject.
			pubAndCheck := func(subj, filterSubject, seq string, ok bool) {
				t.Helper()
				m := nats.NewMsg(subj)
				m.Data = []byte("HELLO")

				// Expect last to be seq.
				m.Header.Set(JSExpectedLastSubjSeq, seq)

				// Constrain the sequence restriction to a specific subject
				// e.g. "kv.1.*" for kv.1.foo, kv.1.bar, kv.1.baz; kv.2.* for kv.2.foo, kv.2.baz; kv.3.* for kv.3.bar
				m.Header.Set(JSExpectedLastSubjSeqSubj, filterSubject)
				_, err := js.PublishMsg(m)
				if ok && err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				if !ok && err == nil {
					t.Fatalf("Expected to get an error and got none")
				}
			}

			pubAndCheck("kv.1.foo", "kv.1.*", "0", false)
			pubAndCheck("kv.1.bar", "kv.1.*", "0", false)
			pubAndCheck("kv.1.xxx", "kv.1.*", "0", false)
			pubAndCheck("kv.1.foo", "kv.1.*", "1", false)
			pubAndCheck("kv.1.bar", "kv.1.*", "1", false)
			pubAndCheck("kv.1.xxx", "kv.1.*", "1", false)
			pubAndCheck("kv.2.foo", "kv.2.*", "1", false)
			pubAndCheck("kv.2.bar", "kv.2.*", "1", false)
			pubAndCheck("kv.2.xxx", "kv.2.*", "1", false)
			pubAndCheck("kv.1.bar", "kv.1.*", "2", false)
			pubAndCheck("kv.1.bar", "kv.1.*", "3", false)
			pubAndCheck("kv.1.bar", "kv.1.*", "4", false)
			pubAndCheck("kv.1.bar", "kv.1.*", "5", false)
			pubAndCheck("kv.1.bar", "kv.1.*", "6", true) // Last is 8 for kv.1.bar; 8 for kv.1.*;
			pubAndCheck("kv.1.baz", "kv.1.*", "2", false)
			pubAndCheck("kv.1.bar", "kv.1.*", "7", false)
			pubAndCheck("kv.1.xxx", "kv.1.*", "8", true) // Last is 9 for kv.1.xxx; 9 for kv.1.*;
			pubAndCheck("kv.2.foo", "kv.2.*", "2", false)
			pubAndCheck("kv.2.foo", "kv.2.*", "7", true)  // Last is 10 for kv.2.foo; 10 for kv.2.*;
			pubAndCheck("kv.xxx", "kv.*", "0", true)      // Last is 0 for kv.xxx; 0 for kv.*;
			pubAndCheck("kv.xxx", "kv.*.*", "0", false)   // Last is 11 for kv.xxx; 11 for kv.*.*;
			pubAndCheck("kv.3.xxx", "kv.3.*", "4", true)  // Last is 12 for kv.3.xxx; 12 for kv.3.*;
			pubAndCheck("kv.3.xyz", "kv.3.*", "12", true) // Last is 13 for kv.3.xyz; 13 for kv.3.*;

			// When using the last-subj-seq-subj header, but the sequence header is missing.
			m = nats.NewMsg("kv.invalid")
			m.Data = []byte("HELLO")
			m.Header.Set(JSExpectedLastSubjSeqSubj, "kv.invalid")
			_, err = js.PublishMsg(m)
			require_Error(t, err, NewJSStreamExpectedLastSeqPerSubjectInvalidError())
		})
	}

	for _, replicas := range []int{1, 3} {
		for _, st := range []StorageType{FileStorage, MemoryStorage} {
			test(replicas, st)
		}
	}
}

func TestJetStreamFilteredConsumersWithWiderFilter(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Origin
	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo", "bar", "baz", "N.*"},
	})
	require_NoError(t, err)

	// Add in some messages.
	js.Publish("foo", []byte("OK"))
	js.Publish("bar", []byte("OK"))
	js.Publish("baz", []byte("OK"))
	for i := 0; i < 12; i++ {
		js.Publish(fmt.Sprintf("N.%d", i+1), []byte("OK"))
	}

	checkFor(t, 5*time.Second, 250*time.Millisecond, func() error {
		si, err := js.StreamInfo("TEST")
		require_NoError(t, err)

		if si.State.Msgs != 15 {
			return fmt.Errorf("Expected 15 msgs, got state: %+v", si.State)
		}
		return nil
	})

	checkWider := func(subj string, numExpected int) {
		sub, err := js.SubscribeSync(subj)
		require_NoError(t, err)

		defer sub.Unsubscribe()
		checkSubsPending(t, sub, numExpected)
	}

	checkWider("*", 3)
	checkWider("N.*", 12)
	checkWider("*.*", 12)
	checkWider("N.>", 12)
	checkWider(">", 15)
}

func TestJetStreamMirrorAndSourcesFilteredConsumers(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Origin
	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo", "bar", "baz.*"},
	})
	require_NoError(t, err)

	// Create Mirror now.
	_, err = js.AddStream(&nats.StreamConfig{
		Name:   "M",
		Mirror: &nats.StreamSource{Name: "TEST"},
	})
	require_NoError(t, err)

	dsubj := nats.NewInbox()
	nc.SubscribeSync(dsubj)
	nc.Flush()

	createConsumer := func(sn, fs string) {
		t.Helper()
		_, err = js.AddConsumer(sn, &nats.ConsumerConfig{DeliverSubject: dsubj, FilterSubject: fs})
		require_NoError(t, err)

	}

	createConsumer("M", "foo")
	createConsumer("M", "bar")
	createConsumer("M", "baz.foo")

	// Now do some sources.
	if _, err := js.AddStream(&nats.StreamConfig{Name: "O1", Subjects: []string{"foo.*"}}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if _, err := js.AddStream(&nats.StreamConfig{Name: "O2", Subjects: []string{"bar.*"}}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// Create Mirror now.
	_, err = js.AddStream(&nats.StreamConfig{
		Name:    "S",
		Sources: []*nats.StreamSource{{Name: "O1"}, {Name: "O2"}},
	})
	require_NoError(t, err)

	createConsumer("S", "foo.1")
	createConsumer("S", "bar.1")

	// Chaining
	// Create Mirror now.
	_, err = js.AddStream(&nats.StreamConfig{
		Name:   "M2",
		Mirror: &nats.StreamSource{Name: "M"},
	})
	require_NoError(t, err)

	createConsumer("M2", "foo")
	createConsumer("M2", "bar")
	createConsumer("M2", "baz.foo")
}

func TestJetStreamMirrorBasics(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	createStream := func(cfg *nats.StreamConfig) (*nats.StreamInfo, error) {
		return js.AddStream(cfg)
	}

	createStreamOk := func(cfg *nats.StreamConfig) {
		t.Helper()
		if _, err := createStream(cfg); err != nil {
			t.Fatalf("Expected no error, got %+v", err)
		}
	}

	// Test we get right config errors etc.
	cfg := &nats.StreamConfig{
		Name:     "M1",
		Subjects: []string{"foo", "bar", "baz"},
		Mirror:   &nats.StreamSource{Name: "S1"},
	}
	_, err := createStream(cfg)
	if err == nil || !strings.Contains(err.Error(), "stream mirrors can not") {
		t.Fatalf("Expected error, got %+v", err)
	}

	// Clear subjects.
	cfg.Subjects = nil

	// Mirrored
	scfg := &nats.StreamConfig{
		Name:     "S1",
		Subjects: []string{"foo", "bar", "baz"},
	}

	// Create mirrored stream
	createStreamOk(scfg)

	// Now create our mirror stream.
	createStreamOk(cfg)

	// For now wait for the consumer state to register.
	time.Sleep(250 * time.Millisecond)

	// Send 100 messages.
	for i := 0; i < 100; i++ {
		if _, err := js.Publish("foo", []byte("OK")); err != nil {
			t.Fatalf("Unexpected publish error: %v", err)
		}
	}

	// Faster timeout since we loop below checking for condition.
	js2, err := nc.JetStream(nats.MaxWait(500 * time.Millisecond))
	require_NoError(t, err)

	checkFor(t, 5*time.Second, 250*time.Millisecond, func() error {
		si, err := js2.StreamInfo("M1")
		require_NoError(t, err)

		if si.State.Msgs != 100 {
			return fmt.Errorf("Expected 100 msgs, got state: %+v", si.State)
		}
		return nil
	})

	// Purge the mirrored stream.
	if err := js.PurgeStream("S1"); err != nil {
		t.Fatalf("Unexpected purge error: %v", err)
	}
	// Send 50 more msgs now.
	for i := 0; i < 50; i++ {
		if _, err := js.Publish("bar", []byte("OK")); err != nil {
			t.Fatalf("Unexpected publish error: %v", err)
		}
	}

	cfg = &nats.StreamConfig{
		Name:    "M2",
		Storage: nats.FileStorage,
		Mirror:  &nats.StreamSource{Name: "S1"},
	}

	// Now create our second mirror stream.
	createStreamOk(cfg)

	checkFor(t, 5*time.Second, 250*time.Millisecond, func() error {
		si, err := js2.StreamInfo("M2")
		require_NoError(t, err)

		if si.State.Msgs != 50 {
			return fmt.Errorf("Expected 50 msgs, got state: %+v", si.State)
		}
		if si.State.FirstSeq != 101 {
			return fmt.Errorf("Expected start seq of 101, got state: %+v", si.State)
		}
		return nil
	})

	// Send 100 more msgs now. Should be 150 total, 101 first.
	for i := 0; i < 100; i++ {
		if _, err := js.Publish("baz", []byte("OK")); err != nil {
			t.Fatalf("Unexpected publish error: %v", err)
		}
	}

	cfg = &nats.StreamConfig{
		Name:   "M3",
		Mirror: &nats.StreamSource{Name: "S1", OptStartSeq: 150},
	}

	createStreamOk(cfg)

	checkFor(t, 5*time.Second, 250*time.Millisecond, func() error {
		si, err := js2.StreamInfo("M3")
		require_NoError(t, err)

		if si.State.Msgs != 101 {
			return fmt.Errorf("Expected 101 msgs, got state: %+v", si.State)
		}
		if si.State.FirstSeq != 150 {
			return fmt.Errorf("Expected start seq of 150, got state: %+v", si.State)
		}
		return nil
	})

	// Make sure setting time works ok.
	start := time.Now().UTC().Add(-2 * time.Hour)
	cfg = &nats.StreamConfig{
		Name:   "M4",
		Mirror: &nats.StreamSource{Name: "S1", OptStartTime: &start},
	}
	createStreamOk(cfg)

	checkFor(t, 5*time.Second, 250*time.Millisecond, func() error {
		si, err := js2.StreamInfo("M4")
		require_NoError(t, err)

		if si.State.Msgs != 150 {
			return fmt.Errorf("Expected 150 msgs, got state: %+v", si.State)
		}
		if si.State.FirstSeq != 101 {
			return fmt.Errorf("Expected start seq of 101, got state: %+v", si.State)
		}
		return nil
	})

	// Test subject filtering and transformation
	createStreamServerStreamConfig := func(cfg *StreamConfig, errToCheck uint16) {
		t.Helper()
		req, err := json.Marshal(cfg)
		require_NoError(t, err)

		rm, err := nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
		require_NoError(t, err)

		var resp JSApiStreamCreateResponse
		if err := json.Unmarshal(rm.Data, &resp); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		if errToCheck == 0 {
			if resp.Error != nil {
				t.Fatalf("Unexpected error: %+v", resp.Error)
			}
		} else {
			if resp.Error.ErrCode != errToCheck {
				t.Fatalf("Expected error %+v, got: %+v", errToCheck, resp.Error)
			}
		}
	}

	// check for errors
	createStreamServerStreamConfig(&StreamConfig{
		Name:    "MBAD",
		Storage: FileStorage,
		Mirror:  &StreamSource{Name: "S1", FilterSubject: "foo", SubjectTransforms: []SubjectTransformConfig{{Source: "foo", Destination: "foo3"}}},
	}, ApiErrors[JSMirrorMultipleFiltersNotAllowed].ErrCode)

	createStreamServerStreamConfig(&StreamConfig{
		Name:    "MBAD",
		Storage: FileStorage,
		Mirror:  &StreamSource{Name: "S1", SubjectTransforms: []SubjectTransformConfig{{Source: ".*.", Destination: "foo3"}}},
	}, ApiErrors[JSMirrorInvalidSubjectFilter].ErrCode)

	createStreamServerStreamConfig(&StreamConfig{
		Name:    "MBAD",
		Storage: FileStorage,
		Mirror:  &StreamSource{Name: "S1", SubjectTransforms: []SubjectTransformConfig{{Source: "*", Destination: "{{wildcard(2)}}"}}},
	}, ApiErrors[JSMirrorInvalidTransformDestination].ErrCode)

	createStreamServerStreamConfig(&StreamConfig{
		Name:    "MBAD",
		Storage: FileStorage,
		Mirror:  &StreamSource{Name: "S1", SubjectTransforms: []SubjectTransformConfig{{Source: "foo", Destination: ""}, {Source: "foo", Destination: "bar"}}},
	}, ApiErrors[JSMirrorOverlappingSubjectFilters].ErrCode)

	createStreamServerStreamConfig(&StreamConfig{
		Name:    "M5",
		Storage: FileStorage,
		Mirror:  &StreamSource{Name: "S1", SubjectTransforms: []SubjectTransformConfig{{Source: "foo", Destination: "foo2"}}},
	}, 0)

	createStreamServerStreamConfig(&StreamConfig{
		Name:    "M6",
		Storage: FileStorage,
		Mirror:  &StreamSource{Name: "S1", SubjectTransforms: []SubjectTransformConfig{{Source: "bar", Destination: "bar2"}, {Source: "baz", Destination: "baz2"}}},
	}, 0)

	// Send 100 messages on foo (there should already be 50 messages on bar and 100 on baz in the stream)
	for i := 0; i < 100; i++ {
		if _, err := js.Publish("foo", []byte("OK")); err != nil {
			t.Fatalf("Unexpected publish error: %v", err)
		}
	}

	var f = func(streamName string, subject string, subjectNumMsgs uint64, streamNumMsg uint64, firstSeq uint64, lastSeq uint64) func() error {
		return func() error {
			si, err := js2.StreamInfo(streamName, &nats.StreamInfoRequest{SubjectsFilter: subject})
			require_NoError(t, err)
			if ss, ok := si.State.Subjects[subject]; !ok {
				return fmt.Errorf("expected messages with the transformed subject %s", subject)
			} else {
				if ss != subjectNumMsgs {
					return fmt.Errorf("expected %d messages on the transformed subject %s but got %d", subjectNumMsgs, subject, ss)
				}
			}
			if si.State.Msgs != streamNumMsg {
				return fmt.Errorf("expected %d stream messages, got state: %+v", streamNumMsg, si.State)
			}
			if si.State.FirstSeq != firstSeq || si.State.LastSeq != lastSeq {
				return fmt.Errorf("expected first sequence=%d and last sequence=%d, but got state: %+v", firstSeq, lastSeq, si.State)
			}
			return nil
		}
	}

	checkFor(t, 10*time.Second, 500*time.Millisecond, f("M5", "foo2", 100, 100, 251, 350))
	checkFor(t, 10*time.Second, 500*time.Millisecond, f("M6", "bar2", 50, 150, 101, 250))
	checkFor(t, 10*time.Second, 500*time.Millisecond, f("M6", "baz2", 100, 150, 101, 250))

}

func TestJetStreamMirrorStripExpectedHeaders(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Create source and mirror streams.
	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "S",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)
	_, err = js.AddStream(&nats.StreamConfig{
		Name:   "M",
		Mirror: &nats.StreamSource{Name: "S"},
	})
	require_NoError(t, err)

	m := nats.NewMsg("foo")
	pubAck, err := js.PublishMsg(m)
	require_NoError(t, err)
	require_Equal(t, pubAck.Sequence, 1)

	// Mirror should get message.
	checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
		if si, err := js.StreamInfo("M"); err != nil {
			return err
		} else if si.State.Msgs != 1 {
			return fmt.Errorf("expected 1 mirrored msg, got %d", si.State.Msgs)
		}
		return nil
	})

	m.Header.Set("Nats-Expected-Stream", "S")
	pubAck, err = js.PublishMsg(m)
	require_NoError(t, err)
	require_Equal(t, pubAck.Sequence, 2)

	// Mirror should strip expected headers and store the message.
	checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
		if si, err := js.StreamInfo("M"); err != nil {
			return err
		} else if si.State.Msgs != 2 {
			return fmt.Errorf("expected 2 mirrored msgs, got %d", si.State.Msgs)
		}
		return nil
	})
}

func TestJetStreamMirrorUpdatePreventsSubjects(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "ORIGINAL"})
	require_NoError(t, err)

	_, err = js.AddStream(&nats.StreamConfig{Name: "MIRROR", Mirror: &nats.StreamSource{Name: "ORIGINAL"}})
	require_NoError(t, err)

	_, err = js.UpdateStream(&nats.StreamConfig{Name: "MIRROR", Mirror: &nats.StreamSource{Name: "ORIGINAL"}, Subjects: []string{"x"}})
	if err == nil || err.Error() != "nats: stream mirrors can not contain subjects" {
		t.Fatalf("Expected to not be able to put subjects on a stream, got: %+v", err)
	}
}

func TestJetStreamSourceBasics(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	createStream := func(cfg *StreamConfig) {
		t.Helper()
		req, err := json.Marshal(cfg)
		require_NoError(t, err)

		rm, err := nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
		require_NoError(t, err)

		var resp JSApiStreamCreateResponse
		if err := json.Unmarshal(rm.Data, &resp); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if resp.Error != nil {
			t.Fatalf("Unexpected error: %+v", resp.Error)
		}
	}

	if _, err := js.AddStream(&nats.StreamConfig{Name: "test", Sources: []*nats.StreamSource{{Name: ""}}}); err.Error() == "source stream name is invalid" {
		t.Fatal("Expected a source stream name is invalid error")
	}

	for _, sname := range []string{"foo", "bar", "baz"} {
		if _, err := js.AddStream(&nats.StreamConfig{Name: sname}); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
	}
	sendBatch := func(subject string, n int) {
		for i := 0; i < n; i++ {
			if _, err := js.Publish(subject, []byte("OK")); err != nil {
				t.Fatalf("Unexpected publish error: %v", err)
			}
		}
	}
	// Populate each one.
	sendBatch("foo", 10)
	sendBatch("bar", 15)
	sendBatch("baz", 25)

	cfg := &StreamConfig{
		Name:    "MS",
		Storage: FileStorage,
		Sources: []*StreamSource{
			{Name: "foo", SubjectTransforms: []SubjectTransformConfig{{Source: ">", Destination: "foo2.>"}}},
			{Name: "bar"},
			{Name: "baz"},
		},
	}

	createStream(cfg)

	// Faster timeout since we loop below checking for condition.
	js2, err := nc.JetStream(nats.MaxWait(250 * time.Millisecond))
	require_NoError(t, err)

	checkFor(t, 2*time.Second, 100*time.Millisecond, func() error {
		si, err := js2.StreamInfo("MS")
		require_NoError(t, err)

		if si.State.Msgs != 50 {
			return fmt.Errorf("Expected 50 msgs, got state: %+v", si.State)
		}
		return nil
	})

	ss, err := js.SubscribeSync("foo2.foo", nats.BindStream("MS"))
	require_NoError(t, err)
	// we must have at least one message on the transformed subject name (ie no timeout)
	_, err = ss.NextMsg(time.Millisecond)
	require_NoError(t, err)
	ss.Drain()

	// Test Source Updates
	ncfg := &nats.StreamConfig{
		Name: "MS",
		Sources: []*nats.StreamSource{
			// Keep foo, bar, remove baz, add dlc
			{Name: "foo"},
			{Name: "bar"},
			{Name: "dlc"},
		},
	}
	if _, err := js.UpdateStream(ncfg); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// Test optional start times, filtered subjects etc.
	if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST", Subjects: []string{"dlc", "rip", "jnm"}}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	sendBatch("dlc", 20)
	sendBatch("rip", 20)
	sendBatch("dlc", 10)
	sendBatch("jnm", 10)

	cfg = &StreamConfig{
		Name:    "FMS",
		Storage: FileStorage,
		Sources: []*StreamSource{
			{Name: "TEST", OptStartSeq: 26},
		},
	}
	createStream(cfg)
	checkFor(t, 2*time.Second, 100*time.Millisecond, func() error {
		si, err := js2.StreamInfo("FMS")
		require_NoError(t, err)
		if si.State.Msgs != 35 {
			return fmt.Errorf("Expected 35 msgs, got state: %+v", si.State)
		}
		return nil
	})
	// Double check first starting.
	m, err := js.GetMsg("FMS", 1)
	require_NoError(t, err)
	if shdr := m.Header.Get(JSStreamSource); shdr == _EMPTY_ {
		t.Fatalf("Expected a header, got none")
	} else if _, _, sseq := streamAndSeq(shdr); sseq != 26 {
		t.Fatalf("Expected header sequence of 26, got %d", sseq)
	}

	// Test Filters
	cfg = &StreamConfig{
		Name:    "FMS2",
		Storage: FileStorage,
		Sources: []*StreamSource{
			{Name: "TEST", OptStartSeq: 11, SubjectTransforms: []SubjectTransformConfig{{Source: "dlc", Destination: "dlc2"}}},
		},
	}
	createStream(cfg)
	checkFor(t, 2*time.Second, 100*time.Millisecond, func() error {
		si, err := js2.StreamInfo("FMS2")
		require_NoError(t, err)
		if si.State.Msgs != 20 {
			return fmt.Errorf("Expected 20 msgs, got state: %+v", si.State)
		}
		return nil
	})

	// Double check first starting.
	if m, err = js.GetMsg("FMS2", 1); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if shdr := m.Header.Get(JSStreamSource); shdr == _EMPTY_ {
		t.Fatalf("Expected a header, got none")
	} else if _, _, sseq := streamAndSeq(shdr); sseq != 11 {
		t.Fatalf("Expected header sequence of 11, got %d", sseq)
	}
	if m.Subject != "dlc2" {
		t.Fatalf("Expected transformed subject dlc2, but got %s instead", m.Subject)
	}

	// Test Filters
	cfg = &StreamConfig{
		Name:    "FMS3",
		Storage: FileStorage,
		Sources: []*StreamSource{
			{Name: "TEST", SubjectTransforms: []SubjectTransformConfig{{Source: "dlc", Destination: "dlc2"}, {Source: "rip", Destination: ""}}},
		},
	}
	createStream(cfg)
	checkFor(t, 2*time.Second, 100*time.Millisecond, func() error {
		si, err := js2.StreamInfo("FMS3")
		require_NoError(t, err)
		if si.State.Msgs != 50 {
			return fmt.Errorf("Expected 50 msgs, got state: %+v", si.State)
		}
		return nil
	})

	// Double check first message
	if m, err = js.GetMsg("FMS3", 1); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if shdr := m.Header.Get(JSStreamSource); shdr == _EMPTY_ {
		t.Fatalf("Expected a header, got none")
	} else if m.Subject != "dlc2" {
		t.Fatalf("Expected subject 'dlc2' and got %s", m.Subject)
	}

	// Double check first message with the other subject
	if m, err = js.GetMsg("FMS3", 21); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	if shdr := m.Header.Get(JSStreamSource); shdr == _EMPTY_ {
		t.Fatalf("Expected a header, got none")
	} else if m.Subject != "rip" {
		t.Fatalf("Expected subject 'rip' and got %s", m.Subject)
	}

	checkFor(t, 2*time.Second, 100*time.Millisecond, func() error {
		si, err := js2.StreamInfo("FMS3")
		require_NoError(t, err)
		if si.State.Subjects["jnm"] != 0 {
			return fmt.Errorf("Unexpected messages from the source found")
		}
		return nil
	})

	// pre 2.10 backwards compatibility
	transformConfig := nats.SubjectTransformConfig{Source: "B.*", Destination: "A.{{Wildcard(1)}}"}
	aConfig := nats.StreamConfig{Name: "A", Subjects: []string{"B.*"}, SubjectTransform: &transformConfig}
	if _, err := js.AddStream(&aConfig); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	sendBatch("B.A", 1)
	sendBatch("B.B", 1)
	bConfig := nats.StreamConfig{Name: "B", Subjects: []string{"A.*"}}

	if _, err := js.AddStream(&bConfig); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// fake a message that would have been sourced with pre 2.10
	msg := nats.NewMsg("A.A")
	// pre 2.10 header format just stream name and sequence number
	msg.Header.Set(JSStreamSource, "A 1")
	msg.Data = []byte("OK")

	if _, err := js.PublishMsg(msg); err != nil {
		t.Fatalf("Unexpected publish error: %v", err)
	}

	bConfig.Sources = []*nats.StreamSource{{Name: "A"}}
	if _, err := js.UpdateStream(&bConfig); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	checkFor(t, 2*time.Second, 100*time.Millisecond, func() error {
		si, err := js2.StreamInfo("B")
		require_NoError(t, err)
		if si.State.Msgs != 2 {
			return fmt.Errorf("Expected 2 msgs, got state: %+v", si.State)
		}
		return nil
	})
}

func TestJetStreamSourceWorkingQueueWithLimit(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "test", Subjects: []string{"test"}})
	require_NoError(t, err)

	_, err = js.AddStream(&nats.StreamConfig{Name: "wq", MaxMsgs: 100, Discard: nats.DiscardNew, Retention: nats.WorkQueuePolicy,
		Sources: []*nats.StreamSource{{Name: "test"}}})
	require_NoError(t, err)

	sendBatch := func(subject string, n int) {
		for i := 0; i < n; i++ {
			_, err = js.Publish(subject, []byte("OK"))
			require_NoError(t, err)
		}
	}
	// Populate each one.
	sendBatch("test", 300)

	checkFor(t, 3*time.Second, 250*time.Millisecond, func() error {
		si, err := js.StreamInfo("wq")
		require_NoError(t, err)
		if si.State.Msgs != 100 {
			return fmt.Errorf("Expected 100 msgs, got state: %+v", si.State)
		}
		return nil
	})

	_, err = js.AddConsumer("wq", &nats.ConsumerConfig{Durable: "wqc", FilterSubject: "test", AckPolicy: nats.AckExplicitPolicy})
	require_NoError(t, err)

	ss, err := js.PullSubscribe("test", "wqc", nats.Bind("wq", "wqc"))
	require_NoError(t, err)
	// we must have at least one message on the transformed subject name (ie no timeout)
	f := func(done chan bool) {
		for i := 0; i < 300; i++ {
			m, err := ss.Fetch(1, nats.MaxWait(3*time.Second))
			require_NoError(t, err)
			time.Sleep(11 * time.Millisecond)
			err = m[0].Ack()
			require_NoError(t, err)
		}
		done <- true
	}

	var doneChan = make(chan bool)
	go f(doneChan)

	checkFor(t, 6*time.Second, 100*time.Millisecond, func() error {
		si, err := js.StreamInfo("wq")
		require_NoError(t, err)
		if si.State.Msgs > 0 && si.State.Msgs <= 100 {
			return fmt.Errorf("Expected 0 msgs, got: %d", si.State.Msgs)
		} else if si.State.Msgs > 100 {
			t.Fatalf("Got more than our 100 message limit: %+v", si.State)
		}
		return nil
	})

	select {
	case <-doneChan:
		ss.Drain()
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}
}

func TestJetStreamStreamSourceFromKV(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API reuqests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Create a kv store
	kv, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: "test"})
	require_NoError(t, err)

	// Create a stream with a source from the kv store
	_, err = js.AddStream(&nats.StreamConfig{Name: "test", Retention: nats.InterestPolicy, Sources: []*nats.StreamSource{{Name: "KV_" + kv.Bucket()}}})
	require_NoError(t, err)

	// Create a interested consumer
	_, err = js.AddConsumer("test", &nats.ConsumerConfig{Durable: "durable", AckPolicy: nats.AckExplicitPolicy})
	require_NoError(t, err)

	ss, err := js.PullSubscribe("", "", nats.Bind("test", "durable"))
	require_NoError(t, err)

	rev1, err := kv.Create("key", []byte("value1"))
	require_NoError(t, err)

	m, err := ss.Fetch(1, nats.MaxWait(2*time.Second))
	require_NoError(t, err)
	require_NoError(t, m[0].Ack())
	if string(m[0].Data) != "value1" {
		t.Fatalf("Expected value1, got %s", m[0].Data)
	}

	rev2, err := kv.Update("key", []byte("value2"), rev1)
	require_NoError(t, err)

	_, err = kv.Update("key", []byte("value3"), rev2)
	require_NoError(t, err)

	m, err = ss.Fetch(1, nats.MaxWait(500*time.Millisecond))
	require_NoError(t, err)
	require_NoError(t, m[0].Ack())
	if string(m[0].Data) != "value2" {
		t.Fatalf("Expected value2, got %s", m[0].Data)
	}

	m, err = ss.Fetch(1, nats.MaxWait(500*time.Millisecond))
	require_NoError(t, err)
	require_NoError(t, m[0].Ack())
	if string(m[0].Data) != "value3" {
		t.Fatalf("Expected value3, got %s", m[0].Data)
	}
}

func TestJetStreamInputTransform(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	createStream := func(cfg *StreamConfig) {
		t.Helper()
		req, err := json.Marshal(cfg)
		require_NoError(t, err)

		rm, err := nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
		require_NoError(t, err)

		var resp JSApiStreamCreateResponse
		if err := json.Unmarshal(rm.Data, &resp); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if resp.Error != nil {
			t.Fatalf("Unexpected error: %+v", resp.Error)
		}
	}

	createStream(&StreamConfig{Name: "T1", Subjects: []string{"foo"}, SubjectTransform: &SubjectTransformConfig{Source: ">", Destination: "transformed.>"}, Storage: MemoryStorage})

	// publish a message
	if _, err := js.Publish("foo", []byte("OK")); err != nil {
		t.Fatalf("Unexpected publish error: %v", err)
	}

	m, err := js.GetMsg("T1", 1)
	require_NoError(t, err)

	if m.Subject != "transformed.foo" {
		t.Fatalf("Expected message subject transformed.foo, got %s", m.Subject)
	}
}

func TestJetStreamOperatorAccounts(t *testing.T) {
	s, _ := RunServerWithConfig("./configs/js-op.conf")
	if config := s.JetStreamConfig(); config != nil {
		defer removeDir(t, config.StoreDir)
	}
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s, nats.UserCredentials("./configs/one.creds"))
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST"}); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	toSend := 100
	for i := 0; i < toSend; i++ {
		if _, err := js.Publish("TEST", []byte("OK")); err != nil {
			t.Fatalf("Unexpected publish error: %v", err)
		}
	}

	// Close our user for account one.
	nc.Close()

	// Restart the server.
	s.Shutdown()
	s, _ = RunServerWithConfig("./configs/js-op.conf")
	defer s.Shutdown()

	jsz, err := s.Jsz(nil)
	require_NoError(t, err)

	if jsz.Streams != 1 {
		t.Fatalf("Expected jsz to report our stream on restart")
	}
	if jsz.Messages != uint64(toSend) {
		t.Fatalf("Expected jsz to report our %d messages on restart, got %d", toSend, jsz.Messages)
	}
}

func TestJetStreamServerDomainBadConfig(t *testing.T) {
	shouldFail := func(domain string) {
		t.Helper()
		opts := DefaultTestOptions
		opts.JetStreamDomain = domain
		if err := validateOptions(&opts); err == nil || !strings.Contains(err.Error(), "invalid domain name") {
			t.Fatalf("Expected bad domain error, got %v", err)
		}
	}

	shouldFail("HU..B")
	shouldFail("HU B")
	shouldFail(" ")
	shouldFail("\t")
	shouldFail("CORE.")
	shouldFail(".CORE")
	shouldFail("C.*.O. RE")
	shouldFail("C.ORE")
}

func TestJetStreamServerDomainConfig(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {domain: "HUB", store_dir: %q}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	if !s.JetStreamEnabled() {
		t.Fatalf("Expected JetStream to be enabled")
	}

	config := s.JetStreamConfig()
	if config.Domain != "HUB" {
		t.Fatalf("Expected %q as domain name, got %q", "HUB", config.Domain)
	}
}

func TestJetStreamServerDomainConfigButDisabled(t *testing.T) {
	conf := createConfFile(t, []byte(`
		listen: 127.0.0.1:-1
		jetstream: {domain: "HUB", enabled: false}
	`))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	if s.JetStreamEnabled() {
		t.Fatalf("Expected JetStream NOT to be enabled")
	}

	opts := s.getOpts()
	if opts.JetStreamDomain != "HUB" {
		t.Fatalf("Expected %q as opts domain name, got %q", "HUB", opts.JetStreamDomain)
	}
}

func TestJetStreamDomainInPubAck(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {domain: "HUB", store_dir: %q}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	cfg := &nats.StreamConfig{
		Name:     "TEST",
		Storage:  nats.MemoryStorage,
		Subjects: []string{"foo"},
	}
	if _, err := js.AddStream(cfg); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// Check by hand for now til it makes its way into Go client.
	am, err := nc.Request("foo", nil, time.Second)
	require_NoError(t, err)
	var pa PubAck
	json.Unmarshal(am.Data, &pa)
	if pa.Domain != "HUB" {
		t.Fatalf("Expected PubAck to have domain of %q, got %q", "HUB", pa.Domain)
	}
}

// Issue #2213
func TestJetStreamDirectConsumersBeingReported(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	_, err = js.AddStream(&nats.StreamConfig{
		Name: "S",
		Sources: []*nats.StreamSource{{
			Name: "TEST",
		}},
	})
	require_NoError(t, err)

	if _, err = js.Publish("foo", nil); err != nil {
		t.Fatalf("Unexpected publish error: %v", err)
	}
	checkFor(t, 2*time.Second, 100*time.Millisecond, func() error {
		si, err := js.StreamInfo("S")
		if err != nil {
			return fmt.Errorf("Could not get stream info: %v", err)
		}
		if si.State.Msgs != 1 {
			return fmt.Errorf("Expected 1 msg, got state: %+v", si.State)
		}
		return nil
	})

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)

	// Direct consumers should not be reported
	if si.State.Consumers != 0 {
		t.Fatalf("Did not expect any consumers, got %d", si.State.Consumers)
	}

	// Now check for consumer in consumer names list.
	var names []string
	for name := range js.ConsumerNames("TEST") {
		names = append(names, name)
	}
	if len(names) != 0 {
		t.Fatalf("Expected no consumers but got %+v", names)
	}

	// Now check detailed list.
	var cis []*nats.ConsumerInfo
	for ci := range js.ConsumersInfo("TEST") {
		cis = append(cis, ci)
	}
	if len(cis) != 0 {
		t.Fatalf("Expected no consumers but got %+v", cis)
	}
}

// https://github.com/nats-io/nats-server/issues/2290
func TestJetStreamTemplatedErrorsBug(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	_, err = js.PullSubscribe("foo", "")
	if err != nil && strings.Contains(err.Error(), "{err}") {
		t.Fatalf("Error is not filled in: %v", err)
	}
}

func TestJetStreamServerEncryption(t *testing.T) {
	cases := []struct {
		name   string
		cstr   string
		cipher StoreCipher
	}{
		{"Default", _EMPTY_, ChaCha},
		{"ChaCha", ", cipher: chacha", ChaCha},
		{"AES", ", cipher: aes", AES},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			tmpl := `
				server_name: S22
				listen: 127.0.0.1:-1
				jetstream: {key: $JS_KEY, store_dir: '%s' %s}
			`
			storeDir := t.TempDir()

			conf := createConfFile(t, []byte(fmt.Sprintf(tmpl, storeDir, c.cstr)))

			os.Setenv("JS_KEY", "s3cr3t!!")
			defer os.Unsetenv("JS_KEY")

			s, _ := RunServerWithConfig(conf)
			defer s.Shutdown()

			config := s.JetStreamConfig()
			if config == nil {
				t.Fatalf("Expected config but got none")
			}
			defer removeDir(t, config.StoreDir)

			// Client based API
			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			cfg := &nats.StreamConfig{
				Name:     "TEST",
				Subjects: []string{"foo", "bar", "baz"},
			}
			if _, err := js.AddStream(cfg); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}

			msg := []byte("ENCRYPTED PAYLOAD!!")
			sendMsg := func(subj string) {
				t.Helper()
				if _, err := js.Publish(subj, msg); err != nil {
					t.Fatalf("Unexpected publish error: %v", err)
				}
			}
			// Send 10 msgs
			for i := 0; i < 10; i++ {
				sendMsg("foo")
			}

			// Now create a consumer.
			sub, err := js.PullSubscribe("foo", "dlc")
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			for i, m := range fetchMsgs(t, sub, 10, 5*time.Second) {
				if i < 5 {
					m.AckSync()
				}
			}

			// Grab our state to compare after restart.
			si, _ := js.StreamInfo("TEST")
			ci, _ := js.ConsumerInfo("TEST", "dlc")

			// Quick check to make sure everything not just plaintext still.
			sdir := filepath.Join(config.StoreDir, "$G", "streams", "TEST")
			// Make sure we can not find any plaintext strings in the target file.
			checkFor := func(fn string, strs ...string) {
				t.Helper()
				data, err := os.ReadFile(fn)
				if err != nil {
					t.Fatalf("Unexpected error: %v", err)
				}
				for _, str := range strs {
					if bytes.Contains(data, []byte(str)) {
						t.Fatalf("Found %q in body of file contents", str)
					}
				}
			}
			checkKeyFile := func(fn string) {
				t.Helper()
				if _, err := os.Stat(fn); err != nil {
					t.Fatalf("Expected a key file at %q", fn)
				}
			}

			// Check stream meta.
			checkEncrypted := func() {
				t.Helper()
				checkKeyFile(filepath.Join(sdir, JetStreamMetaFileKey))
				checkFor(filepath.Join(sdir, JetStreamMetaFile), "TEST", "foo", "bar", "baz", "max_msgs", "max_bytes")
				// Check a message block.
				checkKeyFile(filepath.Join(sdir, "msgs", "1.key"))
				checkFor(filepath.Join(sdir, "msgs", "1.blk"), "ENCRYPTED PAYLOAD!!", "foo", "bar", "baz")

				// Check consumer meta and state.
				checkKeyFile(filepath.Join(sdir, "obs", "dlc", JetStreamMetaFileKey))
				checkFor(filepath.Join(sdir, "obs", "dlc", JetStreamMetaFile), "TEST", "dlc", "foo", "bar", "baz", "max_msgs", "ack_policy")
				// Load and see if we can parse the consumer state.
				state, err := os.ReadFile(filepath.Join(sdir, "obs", "dlc", "o.dat"))
				require_NoError(t, err)

				if _, err := decodeConsumerState(state); err == nil {
					t.Fatalf("Expected decoding consumer state to fail")
				}
			}

			// Stop current
			s.Shutdown()

			checkEncrypted()

			// Restart.
			s, _ = RunServerWithConfig(conf)
			defer s.Shutdown()

			// Connect again.
			nc, js = jsClientConnect(t, s)
			defer nc.Close()

			si2, err := js.StreamInfo("TEST")
			require_NoError(t, err)

			if !reflect.DeepEqual(si, si2) {
				t.Fatalf("Stream infos did not match\n%+v\nvs\n%+v", si, si2)
			}

			ci2, _ := js.ConsumerInfo("TEST", "dlc")
			// Consumer create times can be slightly off after restore from disk.
			now := time.Now()
			ci.Created, ci2.Created = now, now
			ci.Delivered.Last, ci2.Delivered.Last = nil, nil
			ci.AckFloor.Last, ci2.AckFloor.Last = nil, nil
			// Also clusters will be different.
			ci.Cluster, ci2.Cluster = nil, nil
			if !reflect.DeepEqual(ci, ci2) {
				t.Fatalf("Consumer infos did not match\n%+v\nvs\n%+v", ci, ci2)
			}

			// Send 10 more msgs
			for i := 0; i < 10; i++ {
				sendMsg("foo")
			}
			if si, err = js.StreamInfo("TEST"); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			if si.State.Msgs != 20 {
				t.Fatalf("Expected 20 msgs total, got %d", si.State.Msgs)
			}

			// Now test snapshots etc.
			acc := s.GlobalAccount()
			mset, err := acc.lookupStream("TEST")
			require_NoError(t, err)
			scfg := mset.config()
			sr, err := mset.snapshot(5*time.Second, false, true)
			if err != nil {
				t.Fatalf("Error getting snapshot: %v", err)
			}
			snapshot, err := io.ReadAll(sr.Reader)
			if err != nil {
				t.Fatalf("Error reading snapshot")
			}

			// Run new server w/o encryption. Make sure we can restore properly (meaning encryption was stripped etc).
			ns := RunBasicJetStreamServer(t)
			defer ns.Shutdown()

			nacc := ns.GlobalAccount()
			r := bytes.NewReader(snapshot)
			mset, err = nacc.RestoreStream(&scfg, r)
			require_NoError(t, err)
			ss := mset.store.State()
			if ss.Msgs != si.State.Msgs || ss.FirstSeq != si.State.FirstSeq || ss.LastSeq != si.State.LastSeq {
				t.Fatalf("Stream states do not match: %+v vs %+v", ss, si.State)
			}

			// Now restore to our encrypted server as well.
			if err := js.DeleteStream("TEST"); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}

			acc = s.GlobalAccount()
			r.Reset(snapshot)
			mset, err = acc.RestoreStream(&scfg, r)
			require_NoError(t, err)
			ss = mset.store.State()
			if ss.Msgs != si.State.Msgs || ss.FirstSeq != si.State.FirstSeq || ss.LastSeq != si.State.LastSeq {
				t.Fatalf("Stream states do not match: %+v vs %+v", ss, si.State)
			}

			// Check that all is encrypted like above since we know we need to convert since snapshots always plaintext.
			checkEncrypted()
		})
	}
}

func TestJetStreamServerEncryptionServerRestarts(t *testing.T) {
	cases := []struct {
		name   string
		cstr   string
		cipher StoreCipher
	}{
		{"Default", _EMPTY_, ChaCha},
		{"ChaCha", ", cipher: chacha", ChaCha},
		{"AES", ", cipher: aes", AES},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			tmpl := `
				server_name: S22
				listen: 127.0.0.1:-1
				jetstream: {key: $JS_KEY, store_dir: '%s' %s}
			`
			storeDir := t.TempDir()

			conf := createConfFile(t, []byte(fmt.Sprintf(tmpl, storeDir, c.cstr)))

			os.Setenv("JS_KEY", "s3cr3t!!")
			defer os.Unsetenv("JS_KEY")

			s, _ := RunServerWithConfig(conf)
			defer s.Shutdown()

			config := s.JetStreamConfig()
			if config == nil {
				t.Fatalf("Expected config but got none")
			}
			defer removeDir(t, config.StoreDir)

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			// Add stream.
			cfg := &nats.StreamConfig{
				Name:     "TEST",
				Subjects: []string{"foo"},
				Storage:  nats.FileStorage,
			}
			_, err := js.AddStream(cfg)
			require_NoError(t, err)

			// Restart to invalidate any in-memory state that adding the stream created.
			s.Shutdown()
			s, _ = RunServerWithConfig(conf)
			defer s.Shutdown()
			nc.Close()
			nc, js = jsClientConnect(t, s)
			defer nc.Close()

			msg := []byte("ENCRYPTED PAYLOAD!!")
			_, err = js.Publish("foo", msg)
			require_NoError(t, err)

			// Restart to invalidate any in-memory state that the publish initialized.
			s.Shutdown()
			s, _ = RunServerWithConfig(conf)
			defer s.Shutdown()
			nc.Close()
			nc, js = jsClientConnect(t, s)
			defer nc.Close()

			// Should still be able to get the data.
			sub, err := js.SubscribeSync("foo")
			require_NoError(t, err)
			defer sub.Drain()

			m, err := sub.NextMsg(time.Second)
			require_NoError(t, err)
			meta, err := m.Metadata()
			require_NoError(t, err)
			require_Equal(t, meta.Sequence.Stream, 1)
		})
	}
}

func TestJetStreamDeliverLastPerSubject(t *testing.T) {
	for _, st := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(st.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			// Client for API requests.
			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			cfg := StreamConfig{
				Name:       "KV",
				Subjects:   []string{"kv.>"},
				Storage:    st,
				MaxMsgsPer: 5,
			}

			req, err := json.Marshal(cfg)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			// Do manually for now.
			nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
			si, err := js.StreamInfo("KV")
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			if si == nil || si.Config.Name != "KV" {
				t.Fatalf("StreamInfo is not correct %+v", si)
			}

			// Interleave them on purpose.
			for i := 1; i <= 11; i++ {
				msg := []byte(fmt.Sprintf("%d", i))
				js.PublishAsync("kv.b1.foo", msg)
				js.PublishAsync("kv.b2.foo", msg)

				js.PublishAsync("kv.b1.bar", msg)
				js.PublishAsync("kv.b2.bar", msg)

				js.PublishAsync("kv.b1.baz", msg)
				js.PublishAsync("kv.b2.baz", msg)
			}

			select {
			case <-js.PublishAsyncComplete():
			case <-time.After(2 * time.Second):
				t.Fatalf("Did not receive completion signal")
			}

			// Do quick check that config needs FilteredSubjects otherwise bad config.
			badReq := CreateConsumerRequest{
				Stream: "KV",
				Config: ConsumerConfig{
					DeliverSubject: "b",
					DeliverPolicy:  DeliverLastPerSubject,
				},
			}
			req, err = json.Marshal(badReq)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			resp, err := nc.Request(fmt.Sprintf(JSApiConsumerCreateT, "KV"), req, time.Second)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			var ccResp JSApiConsumerCreateResponse
			if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			if ccResp.Error == nil || !strings.Contains(ccResp.Error.Description, "filter subject is not set") {
				t.Fatalf("Expected an error, got none")
			}

			// Now let's consume these via last per subject.
			obsReq := CreateConsumerRequest{
				Stream: "KV",
				Config: ConsumerConfig{
					DeliverSubject: "d",
					DeliverPolicy:  DeliverLastPerSubject,
					FilterSubject:  "kv.b1.*",
				},
			}
			req, err = json.Marshal(obsReq)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			resp, err = nc.Request(fmt.Sprintf(JSApiConsumerCreateT, "KV"), req, time.Second)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			ccResp.Error = nil
			if err = json.Unmarshal(resp.Data, &ccResp); err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}

			sub, _ := nc.SubscribeSync("d")
			defer sub.Unsubscribe()

			// Helper to check messages are correct.
			checkNext := func(subject string, sseq uint64, v string) {
				t.Helper()
				m, err := sub.NextMsg(time.Second)
				if err != nil {
					t.Fatalf("Error receiving message: %v", err)
				}
				if m.Subject != subject {
					t.Fatalf("Expected subject %q but got %q", subject, m.Subject)
				}
				meta, err := m.Metadata()
				if err != nil {
					t.Fatalf("didn't get metadata: %s", err)
				}
				if meta.Sequence.Stream != sseq {
					t.Fatalf("Expected stream seq %d but got %d", sseq, meta.Sequence.Stream)
				}
				if string(m.Data) != v {
					t.Fatalf("Expected data of %q but got %q", v, m.Data)
				}
			}

			checkSubsPending(t, sub, 3)

			// Now make sure they are what we expect.
			checkNext("kv.b1.foo", 61, "11")
			checkNext("kv.b1.bar", 63, "11")
			checkNext("kv.b1.baz", 65, "11")

			msg := []byte(fmt.Sprintf("%d", 22))
			js.Publish("kv.b1.bar", msg)
			js.Publish("kv.b2.foo", msg) // Not filtered through..

			checkSubsPending(t, sub, 1)
			checkNext("kv.b1.bar", 67, "22")
		})
	}
}

func TestJetStreamDeliverLastPerSubjectNumPending(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	if _, err := js.AddStream(&nats.StreamConfig{
		Name:              "KV",
		Subjects:          []string{"KV.>"},
		MaxMsgsPerSubject: 5,
		Replicas:          1,
	}); err != nil {
		t.Fatalf("Error adding stream: %v", err)
	}

	for i := 0; i < 5; i++ {
		msg := []byte(fmt.Sprintf("msg%d", i))
		js.Publish("KV.foo", msg)
		js.Publish("KV.bar", msg)
		js.Publish("KV.baz", msg)
		js.Publish("KV.bat", msg)
	}

	// Delete some messages
	js.DeleteMsg("KV", 2)
	js.DeleteMsg("KV", 5)

	ci, err := js.AddConsumer("KV", &nats.ConsumerConfig{
		DeliverSubject: nats.NewInbox(),
		AckPolicy:      nats.AckExplicitPolicy,
		DeliverPolicy:  nats.DeliverLastPerSubjectPolicy,
		FilterSubject:  "KV.>",
	})
	if err != nil {
		t.Fatalf("Error adding consumer: %v", err)
	}
	if ci.NumPending != 4 {
		t.Fatalf("Expected 4 pending msgs, got %v", ci.NumPending)
	}
}

// Issue #2392
func TestJetStreamPurgeEffectsConsumerDelivery(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo.*"},
	})
	require_NoError(t, err)

	js.Publish("foo.a", []byte("show once"))

	sub, err := js.SubscribeSync("foo.*", nats.AckWait(250*time.Millisecond), nats.DeliverAll(), nats.AckExplicit())
	require_NoError(t, err)

	defer sub.Unsubscribe()

	checkSubsPending(t, sub, 1)

	// Do not ack.
	if _, err := sub.NextMsg(time.Second); err != nil {
		t.Fatalf("Error receiving message: %v", err)
	}

	// Now purge stream.
	if err := js.PurgeStream("TEST"); err != nil {
		t.Fatalf("Unexpected purge error: %v", err)
	}

	js.Publish("foo.b", []byte("show twice?"))
	// Do not ack again, should show back up.
	if _, err := sub.NextMsg(time.Second); err != nil {
		t.Fatalf("Error receiving message: %v", err)
	}
	// Make sure we get it back.
	if _, err := sub.NextMsg(time.Second); err != nil {
		t.Fatalf("Error receiving message: %v", err)
	}
}

// Issue #2403
func TestJetStreamExpireCausesDeadlock(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "TEST",
		Subjects:  []string{"foo.*"},
		Storage:   nats.MemoryStorage,
		MaxMsgs:   10,
		Retention: nats.InterestPolicy,
	})
	require_NoError(t, err)

	sub, err := js.SubscribeSync("foo.bar")
	require_NoError(t, err)

	defer sub.Unsubscribe()

	// Publish from two connections to get the write lock request wedged in between
	// having the RLock and wanting it again deeper in the stack.
	nc2, js2 := jsClientConnect(t, s)
	defer nc2.Close()

	for i := 0; i < 1000; i++ {
		js.PublishAsync("foo.bar", []byte("HELLO"))
		js2.PublishAsync("foo.bar", []byte("HELLO"))
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	// If we deadlocked then we will not be able to get stream info.
	if _, err := js.StreamInfo("TEST"); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
}

// Issue #2420
func TestJetStreamDefaultMaxMsgsPer(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	si, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo.*"},
		Storage:  nats.MemoryStorage,
		MaxMsgs:  10,
	})
	require_NoError(t, err)

	if si.Config.MaxMsgsPerSubject != -1 {
		t.Fatalf("Expected default of -1, got %d", si.Config.MaxMsgsPerSubject)
	}
}

// Got a report of streams that expire all messages while the server is down report errors when clients reconnect
// and try to send new messages.
func TestJetStreamExpireAllWhileServerDown(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	cfg := &nats.StreamConfig{
		Name:   "TEST",
		MaxAge: 250 * time.Millisecond,
	}
	if _, err := js.AddStream(cfg); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	toSend := 10_000
	for i := 0; i < toSend; i++ {
		js.PublishAsync("TEST", []byte("OK"))
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()

	time.Sleep(300 * time.Millisecond)

	// Restart after expire.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	if si, err := js.StreamInfo("TEST"); err != nil || si.State.Msgs != 0 {
		t.Fatalf("Unexpected stream info state: %+v", si)
	}

	for i := 0; i < 10; i++ {
		if _, err := js.Publish("TEST", []byte("OK")); err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
	}

	if si, err := js.StreamInfo("TEST"); err != nil || si.State.Msgs != 10 {
		t.Fatalf("Unexpected stream info state: %+v", si)
	}
}

func TestJetStreamLongStreamNamesAndPubAck(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	cfg := &nats.StreamConfig{
		Name:     strings.Repeat("ZABC", 256/4)[:255],
		Subjects: []string{"foo"},
	}
	if _, err := js.AddStream(cfg); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
	js.Publish("foo", []byte("HELLO"))
}

func TestJetStreamPerSubjectPending(t *testing.T) {
	for _, st := range []nats.StorageType{nats.FileStorage, nats.MemoryStorage} {
		t.Run(st.String(), func(t *testing.T) {

			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := js.AddStream(&nats.StreamConfig{
				Name:              "KV_X",
				Subjects:          []string{"$KV.X.>"},
				MaxMsgsPerSubject: 5,
				Storage:           st,
			})
			if err != nil {
				t.Fatalf("add stream failed: %s", err)
			}

			// the message we will care for
			_, err = js.Publish("$KV.X.x.y.z", []byte("hello world"))
			if err != nil {
				t.Fatalf("publish failed: %s", err)
			}

			// make sure there's some unrelated message after
			_, err = js.Publish("$KV.X.1", []byte("hello world"))
			if err != nil {
				t.Fatalf("publish failed: %s", err)
			}

			// we expect the wildcard filter subject to match only the one message and so pending will be 0
			sub, err := js.SubscribeSync("$KV.X.x.>", nats.DeliverLastPerSubject())
			if err != nil {
				t.Fatalf("subscribe failed: %s", err)
			}

			msg, err := sub.NextMsg(time.Second)
			if err != nil {
				t.Fatalf("next failed: %s", err)
			}

			meta, err := msg.Metadata()
			if err != nil {
				t.Fatalf("meta failed: %s", err)
			}

			// with DeliverLastPerSubject set this is never 0, but without setting that its 0 correctly
			if meta.NumPending != 0 {
				t.Fatalf("expected numpending 0 got %d", meta.NumPending)
			}
		})
	}
}

func TestJetStreamPublishExpectNoMsg(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:              "KV",
		Subjects:          []string{"KV.>"},
		MaxMsgsPerSubject: 5,
	})
	if err != nil {
		t.Fatalf("add stream failed: %s", err)
	}

	if _, err = js.Publish("KV.22", []byte("hello world")); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// This should succeed.
	m := nats.NewMsg("KV.33")
	m.Header.Set(JSExpectedLastSubjSeq, "0")
	if _, err := js.PublishMsg(m); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// This should fail.
	m = nats.NewMsg("KV.22")
	m.Header.Set(JSExpectedLastSubjSeq, "0")
	if _, err := js.PublishMsg(m); err == nil {
		t.Fatalf("Expected error: %v", err)
	}

	if err := js.PurgeStream("KV"); err != nil {
		t.Fatalf("Unexpected purge error: %v", err)
	}

	// This should succeed now.
	if _, err := js.PublishMsg(m); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}
}

func TestJetStreamNegativeDupeWindow(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// we incorrectly set MaxAge to -1 which then as a side effect sets dupe window to -1 which should fail
	_, err := js.AddStream(&nats.StreamConfig{
		Name:              "TEST",
		Subjects:          nil,
		Retention:         nats.WorkQueuePolicy,
		MaxConsumers:      1,
		MaxMsgs:           -1,
		MaxBytes:          -1,
		Discard:           nats.DiscardNew,
		MaxAge:            0,
		Duplicates:        -1,
		MaxMsgsPerSubject: -1,
		MaxMsgSize:        -1,
		Storage:           nats.FileStorage,
		Replicas:          1,
		NoAck:             false,
	})
	if err == nil || err.Error() != "nats: duplicates window can not be negative" {
		t.Fatalf("Expected dupe window error got: %v", err)
	}
}

// Issue #2551
func TestJetStreamMirroredConsumerFailAfterRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "S1",
		Storage:  nats.FileStorage,
		Subjects: []string{"foo", "bar", "baz"},
	})
	if err != nil {
		t.Fatalf("create failed: %s", err)
	}

	_, err = js.AddStream(&nats.StreamConfig{
		Name:    "M1",
		Storage: nats.FileStorage,
		Mirror:  &nats.StreamSource{Name: "S1"},
	})
	if err != nil {
		t.Fatalf("create failed: %s", err)
	}

	_, err = js.AddConsumer("M1", &nats.ConsumerConfig{
		Durable:       "C1",
		FilterSubject: ">",
		AckPolicy:     nats.AckExplicitPolicy,
	})
	if err != nil {
		t.Fatalf("consumer create failed: %s", err)
	}

	// Stop current
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	s.WaitForShutdown()

	// Restart.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	_, err = js.StreamInfo("M1")
	if err != nil {
		t.Fatalf("%s did not exist after start: %s", "M1", err)
	}

	_, err = js.ConsumerInfo("M1", "C1")
	if err != nil {
		t.Fatalf("C1 did not exist after start: %s", err)
	}
}

func TestJetStreamDisabledLimitsEnforcementJWT(t *testing.T) {
	updateJwt := func(url string, akp nkeys.KeyPair, pubKey string, jwt string) {
		t.Helper()
		c := natsConnect(t, url, createUserCreds(t, nil, akp))
		defer c.Close()
		if msg, err := c.Request(fmt.Sprintf(accUpdateEventSubjNew, pubKey), []byte(jwt), time.Second); err != nil {
			t.Fatal("error not expected in this test", err)
		} else {
			content := make(map[string]any)
			if err := json.Unmarshal(msg.Data, &content); err != nil {
				t.Fatalf("%v", err)
			} else if _, ok := content["data"]; !ok {
				t.Fatalf("did not get an ok response got: %v", content)
			}
		}
	}
	// create system account
	sysKp, _ := nkeys.CreateAccount()
	sysPub, _ := sysKp.PublicKey()
	// limits to apply and check
	limits1 := jwt.JetStreamLimits{MemoryStorage: 1024, DiskStorage: 0, Streams: 1, Consumer: 2}
	akp, _ := nkeys.CreateAccount()
	aPub, _ := akp.PublicKey()
	claim := jwt.NewAccountClaims(aPub)
	claim.Limits.JetStreamLimits = limits1
	aJwt1, err := claim.Encode(oKp)
	require_NoError(t, err)
	dir := t.TempDir()
	storeDir1 := t.TempDir()
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: -1
		jetstream: {store_dir: '%s'}
		operator: %s
		resolver: {
			type: full
			dir: '%s'
		}
		system_account: %s
    `, storeDir1, ojwt, dir, sysPub)))
	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()
	updateJwt(s.ClientURL(), sysKp, aPub, aJwt1)
	c := natsConnect(t, s.ClientURL(), createUserCreds(t, nil, akp), nats.ReconnectWait(200*time.Millisecond))
	defer c.Close()
	// keep using the same connection
	js, err := c.JetStream()
	require_NoError(t, err)
	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "disk",
		Storage:  nats.FileStorage,
		Subjects: []string{"disk"},
	})
	require_Error(t, err)
}

func TestJetStreamDisabledLimitsEnforcement(t *testing.T) {
	storeDir1 := t.TempDir()
	conf1 := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'}
		accounts {
			one {
				jetstream: {
					mem: 1024
					disk: 0
					streams: 1
					consumers: 2
				}
				users [{user: one, password: password}]
			}
		}
		no_auth_user: one
	`, storeDir1)))
	s, _ := RunServerWithConfig(conf1)
	defer s.Shutdown()

	c := natsConnect(t, s.ClientURL())
	defer c.Close()
	// keep using the same connection
	js, err := c.JetStream()
	require_NoError(t, err)
	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "disk",
		Storage:  nats.FileStorage,
		Subjects: []string{"disk"},
	})
	require_Error(t, err)
}

// Issue #2607
func TestJetStreamPurgeAndFilteredConsumers(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "S", Subjects: []string{"FOO.*"}})
	require_NoError(t, err)

	for i := 0; i < 10; i++ {
		_, err = js.Publish("FOO.adam", []byte("M"))
		require_NoError(t, err)
		_, err = js.Publish("FOO.eve", []byte("F"))
		require_NoError(t, err)
	}

	ci, err := js.AddConsumer("S", &nats.ConsumerConfig{
		Durable:       "adam",
		AckPolicy:     nats.AckExplicitPolicy,
		FilterSubject: "FOO.adam",
	})
	require_NoError(t, err)
	if ci.NumPending != 10 {
		t.Fatalf("Expected NumPending to be 10, got %d", ci.NumPending)
	}

	ci, err = js.AddConsumer("S", &nats.ConsumerConfig{
		Durable:       "eve",
		AckPolicy:     nats.AckExplicitPolicy,
		FilterSubject: "FOO.eve",
	})
	require_NoError(t, err)
	if ci.NumPending != 10 {
		t.Fatalf("Expected NumPending to be 10, got %d", ci.NumPending)
	}

	// Also check unfiltered with interleaving messages.
	_, err = js.AddConsumer("S", &nats.ConsumerConfig{
		Durable:   "all",
		AckPolicy: nats.AckExplicitPolicy,
	})
	require_NoError(t, err)

	// Now purge only adam.
	jr, _ := json.Marshal(&JSApiStreamPurgeRequest{Subject: "FOO.adam"})
	_, err = nc.Request(fmt.Sprintf(JSApiStreamPurgeT, "S"), jr, time.Second)
	require_NoError(t, err)

	si, err := js.StreamInfo("S")
	require_NoError(t, err)
	if si.State.Msgs != 10 {
		t.Fatalf("Expected 10 messages after purge, got %d", si.State.Msgs)
	}

	ci, err = js.ConsumerInfo("S", "eve")
	require_NoError(t, err)
	if ci.NumPending != 10 {
		t.Fatalf("Expected NumPending to be 10, got %d", ci.NumPending)
	}

	ci, err = js.ConsumerInfo("S", "adam")
	require_NoError(t, err)
	if ci.NumPending != 0 {
		t.Fatalf("Expected NumPending to be 0, got %d", ci.NumPending)
	}
	if ci.AckFloor.Stream != 20 {
		t.Fatalf("Expected AckFloor for stream to be 20, got %d", ci.AckFloor.Stream)
	}

	ci, err = js.ConsumerInfo("S", "all")
	require_NoError(t, err)
	if ci.NumPending != 10 {
		t.Fatalf("Expected NumPending to be 10, got %d", ci.NumPending)
	}
}

// Issue #2662
func TestJetStreamLargeExpiresAndServerRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	maxAge := 2 * time.Second

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "S",
		Subjects: []string{"foo"},
		MaxAge:   maxAge,
	})
	require_NoError(t, err)

	start := time.Now()
	_, err = js.Publish("foo", []byte("ok"))
	require_NoError(t, err)

	// Wait total of maxAge - 1s.
	time.Sleep(maxAge - time.Since(start) - time.Second)

	// Stop current
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	// Restart.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	checkFor(t, 5*time.Second, 10*time.Millisecond, func() error {
		si, err := js.StreamInfo("S")
		require_NoError(t, err)
		if si.State.Msgs != 0 {
			return fmt.Errorf("Expected no messages, got %d", si.State.Msgs)
		}
		return nil
	})

	if waited := time.Since(start); waited > maxAge+time.Second {
		t.Fatalf("Waited to long %v vs %v for messages to expire", waited, maxAge)
	}
}

// Bug that was reported showing memstore not handling max per subject of 1.
func TestJetStreamMessagePerSubjectKeepBug(t *testing.T) {
	test := func(t *testing.T, keep int64, store nats.StorageType) {
		s := RunBasicJetStreamServer(t)
		defer s.Shutdown()

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		_, err := js.AddStream(&nats.StreamConfig{
			Name:              "TEST",
			MaxMsgsPerSubject: keep,
			Storage:           store,
		})
		require_NoError(t, err)

		for i := 0; i < 100; i++ {
			_, err = js.Publish("TEST", []byte(fmt.Sprintf("test %d", i)))
			require_NoError(t, err)
		}

		nfo, err := js.StreamInfo("TEST")
		require_NoError(t, err)

		if nfo.State.Msgs != uint64(keep) {
			t.Fatalf("Expected %d message got %d", keep, nfo.State.Msgs)
		}
	}

	t.Run("FileStore", func(t *testing.T) {
		t.Run("Keep 10", func(t *testing.T) { test(t, 10, nats.FileStorage) })
		t.Run("Keep 1", func(t *testing.T) { test(t, 1, nats.FileStorage) })
	})

	t.Run("MemStore", func(t *testing.T) {
		t.Run("Keep 10", func(t *testing.T) { test(t, 10, nats.MemoryStorage) })
		t.Run("Keep 1", func(t *testing.T) { test(t, 1, nats.MemoryStorage) })
	})
}

func TestJetStreamInvalidDeliverSubject(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name: "TEST",
	})
	require_NoError(t, err)

	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{DeliverSubject: " x"})
	require_Error(t, err, NewJSConsumerInvalidDeliverSubjectError())
}

func TestJetStreamMemoryCorruption(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	errCh := make(chan error, 10)
	nc.SetErrorHandler(func(_ *nats.Conn, _ *nats.Subscription, e error) {
		select {
		case errCh <- e:
		default:
		}
	})

	// The storage has to be MemoryStorage to show the issue
	kv, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: "bucket", Storage: nats.MemoryStorage})
	require_NoError(t, err)

	w1, err := kv.WatchAll()
	require_NoError(t, err)

	w2, err := kv.WatchAll(nats.MetaOnly())
	require_NoError(t, err)

	kv.Put("key1", []byte("aaa"))
	kv.Put("key1", []byte("aab"))
	kv.Put("key2", []byte("zza"))
	kv.Put("key2", []byte("zzb"))
	kv.Delete("key1")
	kv.Delete("key2")
	kv.Put("key1", []byte("aac"))
	kv.Put("key2", []byte("zzc"))
	kv.Delete("key1")
	kv.Delete("key2")
	kv.Purge("key1")
	kv.Purge("key2")

	checkUpdates := func(updates <-chan nats.KeyValueEntry) {
		t.Helper()
		count := 0
		for {
			select {
			case <-updates:
				count++
				if count == 13 {
					return
				}
			case <-time.After(time.Second):
				t.Fatal("Did not receive all updates")
			}
		}
	}
	checkUpdates(w1.Updates())
	checkUpdates(w2.Updates())

	select {
	case e := <-errCh:
		t.Fatal(e)
	case <-time.After(250 * time.Millisecond):
		// OK
	}
}

func TestJetStreamRecoverBadStreamSubjects(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()

	f := filepath.Join(sd, "$G", "streams", "TEST")
	fs, err := newFileStore(FileStoreConfig{StoreDir: f}, StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo", "bar", " baz "}, // baz has spaces
		Storage:  FileStorage,
	})
	require_NoError(t, err)
	fs.Stop()

	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)

	if len(si.Config.Subjects) != 3 {
		t.Fatalf("Expected to recover all subjects")
	}
}

func TestJetStreamRecoverBadMirrorConfigWithSubjects(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()
	sd := s.JetStreamConfig().StoreDir

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Origin
	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "S",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	s.Shutdown()

	f := filepath.Join(sd, "$G", "streams", "M")
	fs, err := newFileStore(FileStoreConfig{StoreDir: f}, StreamConfig{
		Name:     "M",
		Subjects: []string{"foo", "bar", "baz"}, // Mirrors should not have spaces.
		Mirror:   &StreamSource{Name: "S"},
		Storage:  FileStorage,
	})
	require_NoError(t, err)
	fs.Stop()

	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	si, err := js.StreamInfo("M")
	require_NoError(t, err)

	if len(si.Config.Subjects) != 0 {
		t.Fatalf("Expected to have NO subjects on mirror")
	}
}

func TestJetStreamCrossAccountsDeliverSubjectInterest(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 4GB, max_file_store: 1TB, store_dir: %q}
		accounts: {
			A: {
				jetstream: enabled
				users: [ {user: a, password: pwd} ]
				exports [
					{ stream: "_d_" }   # For the delivery subject for the consumer
				]
			},
			B: {
				users: [ {user: b, password: pwd} ]
				imports [
					{ stream: { account: A, subject: "_d_"}, to: "foo" }
				]
			},
		}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s, nats.UserInfo("a", "pwd"))
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	msg, toSend := []byte("OK"), 100
	for i := 0; i < toSend; i++ {
		if _, err := js.PublishAsync("foo", msg); err != nil {
			t.Fatalf("Unexpected publish error: %v", err)
		}
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	// Now create the consumer as well here manually that we will want to reference from Account B.
	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{Durable: "dlc", DeliverSubject: "_d_"})
	require_NoError(t, err)

	// Wait to see if the stream import signals to deliver messages with no real subscriber interest.
	time.Sleep(200 * time.Millisecond)

	ci, err := js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)

	// Make sure we have not delivered any messages based on the import signal alone.
	if ci.NumPending != uint64(toSend) || ci.Delivered.Consumer != 0 {
		t.Fatalf("Bad consumer info, looks like we started delivering: %+v", ci)
	}

	// Now create interest in the delivery subject through the import on account B.
	nc, _ = jsClientConnect(t, s, nats.UserInfo("b", "pwd"))
	defer nc.Close()
	sub, err := nc.SubscribeSync("foo")
	require_NoError(t, err)
	checkSubsPending(t, sub, toSend)

	ci, err = js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)

	// Make sure our consumer info reflects we delivered the messages.
	if ci.NumPending != 0 || ci.Delivered.Consumer != uint64(toSend) {
		t.Fatalf("Bad consumer info, looks like we did not deliver: %+v", ci)
	}
}

func TestJetStreamEphemeralPullConsumers(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "EC", Storage: nats.MemoryStorage})
	require_NoError(t, err)

	ci, err := js.AddConsumer("EC", &nats.ConsumerConfig{AckPolicy: nats.AckExplicitPolicy})
	require_NoError(t, err)

	mset, err := s.GlobalAccount().lookupStream("EC")
	require_NoError(t, err)
	o := mset.lookupConsumer(ci.Name)
	if o == nil {
		t.Fatalf("Error looking up consumer %q", ci.Name)
	}
	err = o.setInActiveDeleteThreshold(50 * time.Millisecond)
	require_NoError(t, err)

	time.Sleep(100 * time.Millisecond)
	// Should no longer be around.
	if o := mset.lookupConsumer(ci.Name); o != nil {
		t.Fatalf("Expected consumer to be closed and removed")
	}

	// Make sure timer keeps firing etc. and does not delete until interest is gone.
	ci, err = js.AddConsumer("EC", &nats.ConsumerConfig{AckPolicy: nats.AckExplicitPolicy})
	require_NoError(t, err)
	if o = mset.lookupConsumer(ci.Name); o == nil {
		t.Fatalf("Error looking up consumer %q", ci.Name)
	}
	err = o.setInActiveDeleteThreshold(50 * time.Millisecond)
	require_NoError(t, err)

	// Need interest otherwise the requests will be recycled based on no real interest.
	sub, err := nc.SubscribeSync("xx")
	require_NoError(t, err)

	req := &JSApiConsumerGetNextRequest{Batch: 10, Expires: 250 * time.Millisecond}
	jreq, err := json.Marshal(req)
	require_NoError(t, err)
	rsubj := fmt.Sprintf(JSApiRequestNextT, "EC", ci.Name)
	err = nc.PublishRequest(rsubj, "xx", jreq)
	require_NoError(t, err)
	nc.Flush()

	time.Sleep(100 * time.Millisecond)
	// Should still be alive here.
	if o := mset.lookupConsumer(ci.Name); o == nil {
		t.Fatalf("Expected consumer to still be active")
	}
	// Remove interest.
	sub.Unsubscribe()
	// Make sure this EPC goes away now.
	checkFor(t, 5*time.Second, 10*time.Millisecond, func() error {
		if o := mset.lookupConsumer(ci.Name); o != nil {
			return fmt.Errorf("Consumer still present")
		}
		return nil
	})
}

func TestJetStreamEphemeralPullConsumersInactiveThresholdAndNoWait(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "ECIT", Storage: nats.MemoryStorage})
	require_NoError(t, err)

	ci, err := js.AddConsumer("ECIT", &nats.ConsumerConfig{
		AckPolicy:         nats.AckExplicitPolicy,
		InactiveThreshold: 100 * time.Millisecond,
	})
	require_NoError(t, err)

	// Send 10 no_wait requests every 25ms and consumer should still be present.
	req := &JSApiConsumerGetNextRequest{Batch: 10, NoWait: true}
	jreq, err := json.Marshal(req)
	require_NoError(t, err)
	rsubj := fmt.Sprintf(JSApiRequestNextT, "ECIT", ci.Name)
	for i := 0; i < 10; i++ {
		err = nc.PublishRequest(rsubj, "xx", jreq)
		require_NoError(t, err)
		nc.Flush()
		time.Sleep(25 * time.Millisecond)
	}

	_, err = js.ConsumerInfo("ECIT", ci.Name)
	require_NoError(t, err)
}

func TestJetStreamNakRedeliveryWithNoWait(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	_, err = js.Publish("foo", []byte("NAK"))
	require_NoError(t, err)

	ccReq := &CreateConsumerRequest{
		Stream: "TEST",
		Config: ConsumerConfig{
			Durable:    "dlc",
			AckPolicy:  AckExplicit,
			MaxDeliver: 3,
			AckWait:    time.Minute,
			BackOff:    []time.Duration{5 * time.Second, 10 * time.Second},
		},
	}
	// Do by hand for now until Go client catches up.
	req, err := json.Marshal(ccReq)
	require_NoError(t, err)
	resp, err := nc.Request(fmt.Sprintf(JSApiDurableCreateT, "TEST", "dlc"), req, time.Second)
	require_NoError(t, err)
	var ccResp JSApiConsumerCreateResponse
	err = json.Unmarshal(resp.Data, &ccResp)
	require_NoError(t, err)
	if ccResp.Error != nil {
		t.Fatalf("Unexpected error: %+v", ccResp.Error)
	}

	rsubj := fmt.Sprintf(JSApiRequestNextT, "TEST", "dlc")
	m, err := nc.Request(rsubj, nil, time.Second)
	require_NoError(t, err)

	// NAK this message.
	delay, err := json.Marshal(&ConsumerNakOptions{Delay: 500 * time.Millisecond})
	require_NoError(t, err)
	dnak := []byte(fmt.Sprintf("%s  %s", AckNak, delay))
	m.Respond(dnak)

	// This message should come back to us after 500ms. If we do a one-shot request, with NoWait and Expires
	// this will do the right thing and we get the message.
	// What we want to test here is a true NoWait request with Expires==0 and eventually seeing the message be redelivered.
	expires := time.Now().Add(time.Second)
	for time.Now().Before(expires) {
		m, err = nc.Request(rsubj, []byte(`{"batch":1, "no_wait": true}`), time.Second)
		require_NoError(t, err)
		if len(m.Data) > 0 {
			// We got our message, so we are good.
			return
		}
		// So we do not spin.
		time.Sleep(100 * time.Millisecond)
	}
	t.Fatalf("Did not get the message in time")
}

// Test that we properly enforce per subject msg limits when DiscardNew is set.
// DiscardNew should only apply to stream limits, subject based limits should always be DiscardOld.
func TestJetStreamMaxMsgsPerSubjectWithDiscardNew(t *testing.T) {
	msc := StreamConfig{
		Name:       "TEST",
		Subjects:   []string{"foo", "bar", "baz", "x"},
		Discard:    DiscardNew,
		Storage:    MemoryStorage,
		MaxMsgsPer: 4,
		MaxMsgs:    10,
		MaxBytes:   500,
	}
	fsc := msc
	fsc.Storage = FileStorage

	cases := []struct {
		name    string
		mconfig *StreamConfig
	}{
		{"MemoryStore", &msc},
		{"FileStore", &fsc},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			mset, err := s.GlobalAccount().addStream(c.mconfig)
			require_NoError(t, err)
			defer mset.delete()

			// Client for API requests.
			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			pubAndCheck := func(subj string, num int, expectedNumMsgs uint64) {
				t.Helper()
				for i := 0; i < num; i++ {
					_, err = js.Publish(subj, []byte("TSLA"))
					require_NoError(t, err)
				}
				si, err := js.StreamInfo("TEST")
				require_NoError(t, err)
				if si.State.Msgs != expectedNumMsgs {
					t.Fatalf("Expected %d msgs, got %d", expectedNumMsgs, si.State.Msgs)
				}
			}

			pubExpectErr := func(subj string, sz int) {
				t.Helper()
				_, err = js.Publish(subj, bytes.Repeat([]byte("X"), sz))
				require_Error(t, err, errors.New("nats: maximum bytes exceeded"), errors.New("nats: maximum messages exceeded"))
			}

			pubAndCheck("foo", 1, 1)
			// We should treat this as DiscardOld and only have 4 msgs after.
			pubAndCheck("foo", 4, 4)
			// Same thing here, shoud only have 4 foo and 4 bar for total of 8.
			pubAndCheck("bar", 8, 8)
			// We have 8 here, so only 2 left. If we add in a new subject when we have room it will be accepted.
			pubAndCheck("baz", 2, 10)
			// Now we are full, but makeup is foo-4 bar-4 baz-2.
			// We can add to foo and bar since they are at their max and adding new ones there stays the same in terms of total of 10.
			pubAndCheck("foo", 1, 10)
			pubAndCheck("bar", 1, 10)
			// Try to send a large message under an established subject that will exceed the 500 maximum.
			// Even though we have a bar subject and its at its maximum, the message to be dropped is not big enough, so this should err.
			pubExpectErr("bar", 300)
			// Also even though we have room bytes wise, if we introduce a new subject this should fail too on msg limit exceeded.
			pubExpectErr("x", 2)
		})
	}
}

func TestJetStreamStreamInfoSubjectsDetails(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	getInfo := func(t *testing.T, filter string) *StreamInfo {
		t.Helper()
		// Need to grab StreamInfo by hand for now.
		req, err := json.Marshal(&JSApiStreamInfoRequest{SubjectsFilter: filter})
		require_NoError(t, err)
		resp, err := nc.Request(fmt.Sprintf(JSApiStreamInfoT, "TEST"), req, time.Second)
		require_NoError(t, err)
		var si StreamInfo
		err = json.Unmarshal(resp.Data, &si)
		require_NoError(t, err)
		if si.State.NumSubjects != 3 {
			t.Fatalf("Expected NumSubjects to be 3, but got %d", si.State.NumSubjects)
		}
		return &si
	}

	testSubjects := func(t *testing.T, st nats.StorageType) {
		_, err := js.AddStream(&nats.StreamConfig{
			Name:     "TEST",
			Subjects: []string{"*"},
			Storage:  st,
		})
		require_NoError(t, err)
		defer js.DeleteStream("TEST")

		counts, msg := []int{22, 33, 44}, []byte("ok")
		// Now place msgs, foo-22, bar-33 and baz-44.
		for i, subj := range []string{"foo", "bar", "baz"} {
			for n := 0; n < counts[i]; n++ {
				_, err = js.Publish(subj, msg)
				require_NoError(t, err)
			}
		}

		// Test all subjects first.
		expected := map[string]uint64{"foo": 22, "bar": 33, "baz": 44}
		if si := getInfo(t, nats.AllKeys); !reflect.DeepEqual(si.State.Subjects, expected) {
			t.Fatalf("Expected subjects of %+v, but got %+v", expected, si.State.Subjects)
		}
		if si := getInfo(t, "*"); !reflect.DeepEqual(si.State.Subjects, expected) {
			t.Fatalf("Expected subjects of %+v, but got %+v", expected, si.State.Subjects)
		}
		// Filtered to 1.
		expected = map[string]uint64{"foo": 22}
		if si := getInfo(t, "foo"); !reflect.DeepEqual(si.State.Subjects, expected) {
			t.Fatalf("Expected subjects of %+v, but got %+v", expected, si.State.Subjects)
		}
	}

	t.Run("MemoryStore", func(t *testing.T) { testSubjects(t, nats.MemoryStorage) })
	t.Run("FileStore", func(t *testing.T) { testSubjects(t, nats.FileStorage) })
}

func TestJetStreamStreamInfoSubjectsDetailsWithDeleteAndPurge(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	getInfo := func(t *testing.T, filter string) *StreamInfo {
		t.Helper()
		// Need to grab StreamInfo by hand for now.
		req, err := json.Marshal(&JSApiStreamInfoRequest{SubjectsFilter: filter})
		require_NoError(t, err)
		resp, err := nc.Request(fmt.Sprintf(JSApiStreamInfoT, "TEST"), req, time.Second)
		require_NoError(t, err)
		var si StreamInfo
		err = json.Unmarshal(resp.Data, &si)
		require_NoError(t, err)
		return &si
	}

	checkResults := func(t *testing.T, expected map[string]uint64) {
		t.Helper()
		si := getInfo(t, nats.AllKeys)
		if !reflect.DeepEqual(si.State.Subjects, expected) {
			t.Fatalf("Expected subjects of %+v, but got %+v", expected, si.State.Subjects)
		}
		if si.State.NumSubjects != len(expected) {
			t.Fatalf("Expected NumSubjects to be %d, but got %d", len(expected), si.State.NumSubjects)
		}
	}

	testSubjects := func(t *testing.T, st nats.StorageType) {
		_, err := js.AddStream(&nats.StreamConfig{
			Name:     "TEST",
			Subjects: []string{"*"},
			Storage:  st,
		})
		require_NoError(t, err)
		defer js.DeleteStream("TEST")

		msg := []byte("ok")
		js.Publish("foo", msg) // 1
		js.Publish("foo", msg) // 2
		js.Publish("bar", msg) // 3
		js.Publish("baz", msg) // 4
		js.Publish("baz", msg) // 5
		js.Publish("bar", msg) // 6
		js.Publish("bar", msg) // 7

		checkResults(t, map[string]uint64{"foo": 2, "bar": 3, "baz": 2})

		// Now delete some messages.
		js.DeleteMsg("TEST", 6)

		checkResults(t, map[string]uint64{"foo": 2, "bar": 2, "baz": 2})

		// Delete and add right back, so no-op
		js.DeleteMsg("TEST", 5) // baz
		js.Publish("baz", msg)  // 8

		checkResults(t, map[string]uint64{"foo": 2, "bar": 2, "baz": 2})

		// Now do a purge only of bar.
		jr, _ := json.Marshal(&JSApiStreamPurgeRequest{Subject: "bar"})
		_, err = nc.Request(fmt.Sprintf(JSApiStreamPurgeT, "TEST"), jr, time.Second)
		require_NoError(t, err)

		checkResults(t, map[string]uint64{"foo": 2, "baz": 2})

		// Now purge everything
		err = js.PurgeStream("TEST")
		require_NoError(t, err)

		si := getInfo(t, nats.AllKeys)
		if len(si.State.Subjects) != 0 {
			t.Fatalf("Expected no subjects, but got %+v", si.State.Subjects)
		}
		if si.State.NumSubjects != 0 {
			t.Fatalf("Expected NumSubjects to be 0, but got %d", si.State.NumSubjects)
		}
	}

	t.Run("MemoryStore", func(t *testing.T) { testSubjects(t, nats.MemoryStorage) })
	t.Run("FileStore", func(t *testing.T) { testSubjects(t, nats.FileStorage) })
}

func TestJetStreamStreamInfoSubjectsDetailsAfterRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	getInfo := func(t *testing.T, filter string) *StreamInfo {
		t.Helper()
		// Need to grab StreamInfo by hand for now.
		req, err := json.Marshal(&JSApiStreamInfoRequest{SubjectsFilter: filter})
		require_NoError(t, err)
		resp, err := nc.Request(fmt.Sprintf(JSApiStreamInfoT, "TEST"), req, time.Second)
		require_NoError(t, err)
		var si StreamInfo
		err = json.Unmarshal(resp.Data, &si)
		require_NoError(t, err)
		return &si
	}

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"*"},
	})
	require_NoError(t, err)
	defer js.DeleteStream("TEST")

	msg := []byte("ok")
	js.Publish("foo", msg) // 1
	js.Publish("foo", msg) // 2
	js.Publish("bar", msg) // 3
	js.Publish("baz", msg) // 4
	js.Publish("baz", msg) // 5

	si := getInfo(t, nats.AllKeys)
	if si.State.NumSubjects != 3 {
		t.Fatalf("Expected 3 subjects, but got %d", si.State.NumSubjects)
	}

	// Stop current
	nc.Close()
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	// Restart.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, _ = jsClientConnect(t, s)
	defer nc.Close()

	si = getInfo(t, nats.AllKeys)
	if si.State.NumSubjects != 3 {
		t.Fatalf("Expected 3 subjects, but got %d", si.State.NumSubjects)
	}
}

// Issue #2836
func TestJetStreamInterestRetentionBug(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "TEST",
		Subjects:  []string{"foo.>"},
		Retention: nats.InterestPolicy,
	})
	require_NoError(t, err)

	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{Durable: "c1", AckPolicy: nats.AckExplicitPolicy})
	require_NoError(t, err)

	test := func(token string, fseq, msgs uint64) {
		t.Helper()
		subj := fmt.Sprintf("foo.%s", token)
		_, err = js.Publish(subj, nil)
		require_NoError(t, err)
		si, err := js.StreamInfo("TEST")
		require_NoError(t, err)
		if si.State.FirstSeq != fseq {
			t.Fatalf("Expected first to be %d, got %d", fseq, si.State.FirstSeq)
		}
		if si.State.Msgs != msgs {
			t.Fatalf("Expected msgs to be %d, got %d", msgs, si.State.Msgs)
		}
	}

	test("bar", 1, 1)

	// Create second filtered consumer.
	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{Durable: "c2", FilterSubject: "foo.foo", AckPolicy: nats.AckExplicitPolicy})
	require_NoError(t, err)

	test("bar", 1, 2)
}

// Under load testing for K3S and the KINE interface we saw some stalls.
// These were caused by a dynamic that would not send a second FC item with one
// pending, but when we sent the next message and got blocked, if that msg would
// exceed the outstanding FC we would become stalled.
func TestJetStreamFlowControlStall(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "FC"})
	require_NoError(t, err)

	msg := []byte(strings.Repeat("X", 32768))
	_, err = js.Publish("FC", msg)
	require_NoError(t, err)

	msg = []byte(strings.Repeat("X", 8*32768))
	_, err = js.Publish("FC", msg)
	require_NoError(t, err)
	_, err = js.Publish("FC", msg)
	require_NoError(t, err)

	sub, err := js.SubscribeSync("FC", nats.OrderedConsumer())
	require_NoError(t, err)

	checkSubsPending(t, sub, 3)
}

func TestJetStreamStorageReservedBytes(t *testing.T) {
	const systemLimit = 1024
	opts := DefaultTestOptions
	opts.Port = -1
	opts.JetStream = true
	opts.JetStreamMaxMemory = systemLimit
	opts.JetStreamMaxStore = systemLimit
	opts.StoreDir = t.TempDir()
	opts.HTTPPort = -1
	s := RunServer(&opts)

	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	getJetStreamVarz := func(hc *http.Client, addr string) (JetStreamVarz, error) {
		resp, err := hc.Get(addr)
		if err != nil {
			return JetStreamVarz{}, err
		}
		defer resp.Body.Close()

		var v Varz
		if err := json.NewDecoder(resp.Body).Decode(&v); err != nil {
			return JetStreamVarz{}, err
		}

		return v.JetStream, nil
	}
	getReserved := func(hc *http.Client, addr string, st nats.StorageType) (uint64, error) {
		jsv, err := getJetStreamVarz(hc, addr)
		if err != nil {
			return 0, err
		}
		if st == nats.MemoryStorage {
			return jsv.Stats.ReservedMemory, nil
		}
		return jsv.Stats.ReservedStore, nil
	}

	varzAddr := fmt.Sprintf("http://127.0.0.1:%d/varz", s.MonitorAddr().Port)
	hc := &http.Client{Timeout: 5 * time.Second}

	jsv, err := getJetStreamVarz(hc, varzAddr)
	require_NoError(t, err)

	if got, want := systemLimit, int(jsv.Config.MaxMemory); got != want {
		t.Fatalf("Unexpected max memory: got=%d, want=%d", got, want)
	}
	if got, want := systemLimit, int(jsv.Config.MaxStore); got != want {
		t.Fatalf("Unexpected max store: got=%d, want=%d", got, want)
	}

	cases := []struct {
		name            string
		accountLimit    int64
		storage         nats.StorageType
		createMaxBytes  int64
		updateMaxBytes  int64
		wantUpdateError bool
	}{
		{
			name:           "file reserve 66% of system limit",
			accountLimit:   -1,
			storage:        nats.FileStorage,
			createMaxBytes: int64(math.Round(float64(systemLimit) * .666)),
			updateMaxBytes: int64(math.Round(float64(systemLimit)*.666)) + 1,
		},
		{
			name:           "memory reserve 66% of system limit",
			accountLimit:   -1,
			storage:        nats.MemoryStorage,
			createMaxBytes: int64(math.Round(float64(systemLimit) * .666)),
			updateMaxBytes: int64(math.Round(float64(systemLimit)*.666)) + 1,
		},
		{
			name:            "file update past system limit",
			accountLimit:    -1,
			storage:         nats.FileStorage,
			createMaxBytes:  systemLimit,
			updateMaxBytes:  systemLimit + 1,
			wantUpdateError: true,
		},
		{
			name:            "memory update past system limit",
			accountLimit:    -1,
			storage:         nats.MemoryStorage,
			createMaxBytes:  systemLimit,
			updateMaxBytes:  systemLimit + 1,
			wantUpdateError: true,
		},
		{
			name:           "file update to system limit",
			accountLimit:   -1,
			storage:        nats.FileStorage,
			createMaxBytes: systemLimit - 1,
			updateMaxBytes: systemLimit,
		},
		{
			name:           "memory update to system limit",
			accountLimit:   -1,
			storage:        nats.MemoryStorage,
			createMaxBytes: systemLimit - 1,
			updateMaxBytes: systemLimit,
		},
		{
			name:           "file reserve 66% of account limit",
			accountLimit:   systemLimit / 2,
			storage:        nats.FileStorage,
			createMaxBytes: int64(math.Round(float64(systemLimit/2) * .666)),
			updateMaxBytes: int64(math.Round(float64(systemLimit/2)*.666)) + 1,
		},
		{
			name:           "memory reserve 66% of account limit",
			accountLimit:   systemLimit / 2,
			storage:        nats.MemoryStorage,
			createMaxBytes: int64(math.Round(float64(systemLimit/2) * .666)),
			updateMaxBytes: int64(math.Round(float64(systemLimit/2)*.666)) + 1,
		},
		{
			name:            "file update past account limit",
			accountLimit:    systemLimit / 2,
			storage:         nats.FileStorage,
			createMaxBytes:  (systemLimit / 2),
			updateMaxBytes:  (systemLimit / 2) + 1,
			wantUpdateError: true,
		},
		{
			name:            "memory update past account limit",
			accountLimit:    systemLimit / 2,
			storage:         nats.MemoryStorage,
			createMaxBytes:  (systemLimit / 2),
			updateMaxBytes:  (systemLimit / 2) + 1,
			wantUpdateError: true,
		},
		{
			name:           "file update to account limit",
			accountLimit:   systemLimit / 2,
			storage:        nats.FileStorage,
			createMaxBytes: (systemLimit / 2) - 1,
			updateMaxBytes: (systemLimit / 2),
		},
		{
			name:           "memory update to account limit",
			accountLimit:   systemLimit / 2,
			storage:        nats.MemoryStorage,
			createMaxBytes: (systemLimit / 2) - 1,
			updateMaxBytes: (systemLimit / 2),
		},
	}
	for i := 0; i < len(cases) && !t.Failed(); i++ {
		c := cases[i]
		t.Run(c.name, func(st *testing.T) {
			// Setup limits
			err = s.GlobalAccount().UpdateJetStreamLimits(map[string]JetStreamAccountLimits{
				_EMPTY_: {
					MaxMemory: c.accountLimit,
					MaxStore:  c.accountLimit,
				},
			})
			require_NoError(st, err)

			// Create initial stream
			cfg := &nats.StreamConfig{
				Name:     "TEST",
				Subjects: []string{"foo"},
				Storage:  c.storage,
				MaxBytes: c.createMaxBytes,
			}
			_, err = js.AddStream(cfg)
			require_NoError(st, err)

			// Update stream MaxBytes
			cfg.MaxBytes = c.updateMaxBytes
			info, err := js.UpdateStream(cfg)
			if c.wantUpdateError && err == nil {
				got := info.Config.MaxBytes
				st.Fatalf("Unexpected update success, newMaxBytes=%d; systemLimit=%d; accountLimit=%d",
					got, systemLimit, c.accountLimit)
			} else if !c.wantUpdateError && err != nil {
				st.Fatalf("Unexpected update error: %s", err)
			}

			if !c.wantUpdateError && err == nil {
				// If update was successful, then ensure reserved shows new
				// amount
				reserved, err := getReserved(hc, varzAddr, c.storage)
				require_NoError(st, err)
				if got, want := reserved, uint64(c.updateMaxBytes); got != want {
					st.Fatalf("Unexpected reserved: %d, want %d", got, want)
				}
			}

			// Delete stream
			err = js.DeleteStream("TEST")
			require_NoError(st, err)

			// Ensure reserved shows 0 because we've deleted the stream
			reserved, err := getReserved(hc, varzAddr, c.storage)
			require_NoError(st, err)
			if reserved != 0 {
				st.Fatalf("Unexpected reserved: %d, want 0", reserved)
			}
		})
	}
}

func TestJetStreamRestoreBadStream(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, _ := jsClientConnect(t, s)
	defer nc.Close()

	var rreq JSApiStreamRestoreRequest
	buf, err := os.ReadFile("../test/configs/jetstream/restore_bad_stream/backup.json")
	require_NoError(t, err)
	err = json.Unmarshal(buf, &rreq)
	require_NoError(t, err)

	data, err := os.Open("../test/configs/jetstream/restore_bad_stream/stream.tar.s2")
	require_NoError(t, err)
	defer data.Close()

	var rresp JSApiStreamRestoreResponse
	msg, err := nc.Request(fmt.Sprintf(JSApiStreamRestoreT, rreq.Config.Name), buf, 5*time.Second)
	require_NoError(t, err)
	json.Unmarshal(msg.Data, &rresp)
	if rresp.Error != nil {
		t.Fatalf("Error on restore: %+v", rresp.Error)
	}

	var chunk [1024]byte
	for {
		n, err := data.Read(chunk[:])
		if err == io.EOF {
			break
		}
		require_NoError(t, err)

		msg, err = nc.Request(rresp.DeliverSubject, chunk[:n], 5*time.Second)
		require_NoError(t, err)
		json.Unmarshal(msg.Data, &rresp)
		if rresp.Error != nil {
			t.Fatalf("Error on restore: %+v", rresp.Error)
		}
	}
	msg, err = nc.Request(rresp.DeliverSubject, nil, 5*time.Second)
	require_NoError(t, err)
	json.Unmarshal(msg.Data, &rresp)
	if rresp.Error == nil || !strings.Contains(rresp.Error.Description, "unexpected") {
		t.Fatalf("Expected error about unexpected content, got: %+v", rresp.Error)
	}

	dir := filepath.Join(s.JetStreamConfig().StoreDir, globalAccountName)
	f1 := filepath.Join(dir, "fail1.txt")
	f2 := filepath.Join(dir, "fail2.txt")
	for _, f := range []string{f1, f2} {
		if _, err := os.Stat(f); err == nil {
			t.Fatalf("Found file %s", f)
		}
	}
}

func TestJetStreamRemoveExternalSource(t *testing.T) {
	ho := DefaultTestOptions
	ho.Port = 4000 //-1
	ho.LeafNode.Host = "127.0.0.1"
	ho.LeafNode.Port = -1
	hs := RunServer(&ho)
	defer hs.Shutdown()

	lu, err := url.Parse(fmt.Sprintf("nats://127.0.0.1:%d", ho.LeafNode.Port))
	require_NoError(t, err)

	lo1 := DefaultTestOptions
	lo1.Port = 4111 //-1
	lo1.ServerName = "a-leaf"
	lo1.JetStream = true
	lo1.StoreDir = t.TempDir()
	lo1.JetStreamDomain = "a-leaf"
	lo1.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{lu}}}
	l1 := RunServer(&lo1)
	defer l1.Shutdown()

	lo2 := DefaultTestOptions
	lo2.Port = 2111 //-1
	lo2.ServerName = "b-leaf"
	lo2.JetStream = true
	lo2.StoreDir = t.TempDir()
	lo2.JetStreamDomain = "b-leaf"
	lo2.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{lu}}}
	l2 := RunServer(&lo2)
	defer l2.Shutdown()

	checkLeafNodeConnected(t, l1)
	checkLeafNodeConnected(t, l2)

	checkStreamMsgs := func(js nats.JetStreamContext, stream string, expected uint64) {
		t.Helper()
		checkFor(t, 2*time.Second, 15*time.Millisecond, func() error {
			si, err := js.StreamInfo(stream)
			if err != nil {
				return err
			}
			if si.State.Msgs != expected {
				return fmt.Errorf("Expected %v messages, got %v", expected, si.State.Msgs)
			}
			return nil
		})
	}

	sendToStreamTest := func(js nats.JetStreamContext) {
		t.Helper()
		for i := 0; i < 10; i++ {
			_, err = js.Publish("test", []byte("hello"))
			require_NoError(t, err)
		}
	}

	nca, jsa := jsClientConnect(t, l1)
	defer nca.Close()
	_, err = jsa.AddStream(&nats.StreamConfig{Name: "queue", Subjects: []string{"queue"}})
	require_NoError(t, err)

	_, err = jsa.AddStream(&nats.StreamConfig{Name: "testdel", Subjects: []string{"testdel"}})
	require_NoError(t, err)

	ncb, jsb := jsClientConnect(t, l2)
	defer ncb.Close()
	_, err = jsb.AddStream(&nats.StreamConfig{Name: "test", Subjects: []string{"test"}})
	require_NoError(t, err)
	sendToStreamTest(jsb)
	checkStreamMsgs(jsb, "test", 10)

	_, err = jsb.AddStream(&nats.StreamConfig{Name: "testdelsrc1", Subjects: []string{"testdelsrc1"}})
	require_NoError(t, err)
	_, err = jsb.AddStream(&nats.StreamConfig{Name: "testdelsrc2", Subjects: []string{"testdelsrc2"}})
	require_NoError(t, err)

	// Add test as source to queue
	si, err := jsa.UpdateStream(&nats.StreamConfig{
		Name:     "queue",
		Subjects: []string{"queue"},
		Sources: []*nats.StreamSource{
			{
				Name: "test",
				External: &nats.ExternalStream{
					APIPrefix: "$JS.b-leaf.API",
				},
			},
		},
	})
	require_NoError(t, err)
	require_True(t, len(si.Config.Sources) == 1)
	checkStreamMsgs(jsa, "queue", 10)

	// add more entries to "test"
	sendToStreamTest(jsb)

	// verify entries are both in "test" and "queue"
	checkStreamMsgs(jsb, "test", 20)
	checkStreamMsgs(jsa, "queue", 20)

	// Remove source
	si, err = jsa.UpdateStream(&nats.StreamConfig{
		Name:     "queue",
		Subjects: []string{"queue"},
	})
	require_NoError(t, err)
	require_True(t, len(si.Config.Sources) == 0)

	// add more entries to "test"
	sendToStreamTest(jsb)
	// verify entries are in "test"
	checkStreamMsgs(jsb, "test", 30)

	// But they should not be in "queue". We will wait a bit before checking
	// to make sure that we are letting enough time for the sourcing to
	// incorrectly happen if there is a bug.
	time.Sleep(250 * time.Millisecond)
	checkStreamMsgs(jsa, "queue", 20)

	// Test that we delete correctly. First add source to a "testdel"
	si, err = jsa.UpdateStream(&nats.StreamConfig{
		Name:     "testdel",
		Subjects: []string{"testdel"},
		Sources: []*nats.StreamSource{
			{
				Name: "testdelsrc1",
				External: &nats.ExternalStream{
					APIPrefix: "$JS.b-leaf.API",
				},
			},
		},
	})
	require_NoError(t, err)
	require_True(t, len(si.Config.Sources) == 1)
	// Now add the second one...
	si, err = jsa.UpdateStream(&nats.StreamConfig{
		Name:     "testdel",
		Subjects: []string{"testdel"},
		Sources: []*nats.StreamSource{
			{
				Name: "testdelsrc1",
				External: &nats.ExternalStream{
					APIPrefix: "$JS.b-leaf.API",
				},
			},
			{
				Name: "testdelsrc2",
				External: &nats.ExternalStream{
					APIPrefix: "$JS.b-leaf.API",
				},
			},
		},
	})
	require_NoError(t, err)
	require_True(t, len(si.Config.Sources) == 2)
	// Now check that the stream testdel has still 2 source consumers...
	acc, err := l1.lookupAccount(globalAccountName)
	require_NoError(t, err)
	mset, err := acc.lookupStream("testdel")
	require_NoError(t, err)
	mset.mu.RLock()
	n := len(mset.sources)
	mset.mu.RUnlock()
	if n != 2 {
		t.Fatalf("Expected 2 sources, got %v", n)
	}

	// Restart leaf "a"
	nca.Close()
	l1.Shutdown()
	l1 = RunServer(&lo1)
	defer l1.Shutdown()

	// add more entries to "test"
	sendToStreamTest(jsb)
	checkStreamMsgs(jsb, "test", 40)

	nca, jsa = jsClientConnect(t, l1)
	defer nca.Close()
	time.Sleep(250 * time.Millisecond)
	checkStreamMsgs(jsa, "queue", 20)
}

func TestJetStreamAddStreamWithFilestoreFailure(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Cause failure to create stream with filestore.
	// In one of ipQueue changes, this could cause a panic, so verify that we get
	// a failure to create, but no panic.
	if _, err := s.globalAccount().addStreamWithStore(
		&StreamConfig{Name: "TEST"},
		&FileStoreConfig{BlockSize: 2 * maxBlockSize}); err == nil {
		t.Fatal("Expected failure, did not get one")
	}
}

type checkFastState struct {
	count int64
	StreamStore
}

func (s *checkFastState) FastState(state *StreamState) {
	// Keep track only when called from checkPending()
	if bytes.Contains(debug.Stack(), []byte("checkPending(")) {
		atomic.AddInt64(&s.count, 1)
	}
	s.StreamStore.FastState(state)
}

func TestJetStreamBackOffCheckPending(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: "TEST", Subjects: []string{"foo"}})
	if err != nil {
		t.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	// Plug or store to see how many times we invoke FastState, which is done in checkPending
	mset.mu.Lock()
	st := &checkFastState{StreamStore: mset.store}
	mset.store = st
	mset.mu.Unlock()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	sendStreamMsg(t, nc, "foo", "Hello World!")

	sub, _ := nc.SubscribeSync(nats.NewInbox())
	defer sub.Unsubscribe()
	nc.Flush()

	o, err := mset.addConsumer(&ConsumerConfig{
		DeliverSubject: sub.Subject,
		AckPolicy:      AckExplicit,
		MaxDeliver:     1000,
		BackOff:        []time.Duration{50 * time.Millisecond, 250 * time.Millisecond, time.Second},
	})
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	defer o.delete()

	// Check the first delivery and the following 2 redeliveries
	start := time.Now()
	natsNexMsg(t, sub, time.Second)
	if dur := time.Since(start); dur >= 50*time.Millisecond {
		t.Fatalf("Expected first delivery to be fast, took: %v", dur)
	}
	start = time.Now()
	natsNexMsg(t, sub, time.Second)
	if dur := time.Since(start); dur < 25*time.Millisecond || dur > 75*time.Millisecond {
		t.Fatalf("Expected first redelivery to be ~50ms, took: %v", dur)
	}
	start = time.Now()
	natsNexMsg(t, sub, time.Second)
	if dur := time.Since(start); dur < 200*time.Millisecond || dur > 300*time.Millisecond {
		t.Fatalf("Expected first redelivery to be ~250ms, took: %v", dur)
	}
	// There was a bug that would cause checkPending to be invoked based on the
	// ackWait (which in this case would be the first value of BackOff, which
	// is 50ms). So we would call checkPending() too many times.
	time.Sleep(500 * time.Millisecond)
	// Check now, it should have been invoked twice.
	if n := atomic.LoadInt64(&st.count); n != 2 {
		t.Fatalf("Expected checkPending to be invoked 2 times, was %v", n)
	}
}

func TestJetStreamCrossAccounts(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
        jetstream {
			store_dir = %q
		}
        accounts: {
           A: {
               users: [ {user: a, password: a} ]
               jetstream: enabled
               exports: [
                   {service: '$JS.API.>' }
                   {service: '$KV.>'}
                   {stream: 'accI.>'}
               ]
           },
           I: {
               users: [ {user: i, password: i} ]
               imports: [
                   {service: {account: A, subject: '$JS.API.>'}, to: 'fromA.>' }
                   {service: {account: A, subject: '$KV.>'}, to: 'fromA.$KV.>' }
                   {stream: {subject: 'accI.>', account: A}}
               ]
           }
		}`, t.TempDir())))
	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	watchNext := func(w nats.KeyWatcher) nats.KeyValueEntry {
		t.Helper()
		select {
		case e := <-w.Updates():
			return e
		case <-time.After(time.Second):
			t.Fatal("Fail to get the next update")
		}
		return nil
	}

	nc1, js1 := jsClientConnect(t, s, nats.UserInfo("a", "a"))
	defer nc1.Close()

	kv1, err := js1.CreateKeyValue(&nats.KeyValueConfig{Bucket: "Map", History: 10})
	if err != nil {
		t.Fatalf("Error creating kv store: %v", err)
	}

	w1, err := kv1.Watch("map")
	if err != nil {
		t.Fatalf("Error creating watcher: %v", err)
	}
	if e := watchNext(w1); e != nil {
		t.Fatalf("Expected nil entry, got %+v", e)
	}

	nc2, err := nats.Connect(s.ClientURL(), nats.UserInfo("i", "i"), nats.CustomInboxPrefix("accI"))
	if err != nil {
		t.Fatalf("Error on connect: %v", err)
	}
	defer nc2.Close()
	js2, err := nc2.JetStream(nats.APIPrefix("fromA"))
	if err != nil {
		t.Fatalf("Error getting jetstream context: %v", err)
	}

	kv2, err := js2.CreateKeyValue(&nats.KeyValueConfig{Bucket: "Map", History: 10})
	if err != nil {
		t.Fatalf("Error creating kv store: %v", err)
	}

	w2, err := kv2.Watch("map")
	if err != nil {
		t.Fatalf("Error creating watcher: %v", err)
	}
	if e := watchNext(w2); e != nil {
		t.Fatalf("Expected nil entry, got %+v", e)
	}

	// Do a Put from kv2
	rev, err := kv2.Put("map", []byte("value"))
	if err != nil {
		t.Fatalf("Error on put: %v", err)
	}

	// Get from kv1
	e, err := kv1.Get("map")
	if err != nil {
		t.Fatalf("Error on get: %v", err)
	}
	if e.Key() != "map" || string(e.Value()) != "value" {
		t.Fatalf("Unexpected entry: +%v", e)
	}

	// Get from kv2
	e, err = kv2.Get("map")
	if err != nil {
		t.Fatalf("Error on get: %v", err)
	}
	if e.Key() != "map" || string(e.Value()) != "value" {
		t.Fatalf("Unexpected entry: +%v", e)
	}

	// Watcher 1
	if e := watchNext(w1); e == nil || e.Key() != "map" || string(e.Value()) != "value" {
		t.Fatalf("Unexpected entry: %+v", e)
	}

	// Watcher 2
	if e := watchNext(w2); e == nil || e.Key() != "map" || string(e.Value()) != "value" {
		t.Fatalf("Unexpected entry: %+v", e)
	}

	// Try an update form kv2
	if _, err := kv2.Update("map", []byte("updated"), rev); err != nil {
		t.Fatalf("Failed to update: %v", err)
	}

	// Get from kv1
	e, err = kv1.Get("map")
	if err != nil {
		t.Fatalf("Error on get: %v", err)
	}
	if e.Key() != "map" || string(e.Value()) != "updated" {
		t.Fatalf("Unexpected entry: +%v", e)
	}

	// Get from kv2
	e, err = kv2.Get("map")
	if err != nil {
		t.Fatalf("Error on get: %v", err)
	}
	if e.Key() != "map" || string(e.Value()) != "updated" {
		t.Fatalf("Unexpected entry: +%v", e)
	}

	// Watcher 1
	if e := watchNext(w1); e == nil || e.Key() != "map" || string(e.Value()) != "updated" {
		t.Fatalf("Unexpected entry: %+v", e)
	}

	// Watcher 2
	if e := watchNext(w2); e == nil || e.Key() != "map" || string(e.Value()) != "updated" {
		t.Fatalf("Unexpected entry: %+v", e)
	}

	// Purge from kv2
	if err := kv2.Purge("map"); err != nil {
		t.Fatalf("Error on purge: %v", err)
	}

	// Check purge ok from w1
	if e := watchNext(w1); e == nil || e.Operation() != nats.KeyValuePurge {
		t.Fatalf("Unexpected entry: %+v", e)
	}

	// Check purge ok from w2
	if e := watchNext(w2); e == nil || e.Operation() != nats.KeyValuePurge {
		t.Fatalf("Unexpected entry: %+v", e)
	}

	// Delete purge records from kv2
	if err := kv2.PurgeDeletes(nats.DeleteMarkersOlderThan(-1)); err != nil {
		t.Fatalf("Error on purge deletes: %v", err)
	}

	// Check all gone from js1
	if si, err := js1.StreamInfo("KV_Map"); err != nil || si == nil || si.State.Msgs != 0 {
		t.Fatalf("Error getting stream info: err=%v si=%+v", err, si)
	}

	// Delete key from kv2
	if err := kv2.Delete("map"); err != nil {
		t.Fatalf("Error on delete: %v", err)
	}

	// Check key gone from kv1
	if e, err := kv1.Get("map"); err != nats.ErrKeyNotFound || e != nil {
		t.Fatalf("Expected key not found, got err=%v e=%+v", err, e)
	}
}

func TestJetStreamInvalidRestoreRequests(t *testing.T) {
	test := func(t *testing.T, s *Server, replica int) {
		nc := natsConnect(t, s.ClientURL())
		defer nc.Close()
		// test invalid stream config in restore request
		require_fail := func(cfg StreamConfig, errDesc string) {
			t.Helper()
			rreq := &JSApiStreamRestoreRequest{
				Config: cfg,
			}
			req, err := json.Marshal(rreq)
			require_NoError(t, err)
			rmsg, err := nc.Request(fmt.Sprintf(JSApiStreamRestoreT, "fail"), req, time.Second)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			var rresp JSApiStreamRestoreResponse
			json.Unmarshal(rmsg.Data, &rresp)
			require_True(t, rresp.Error != nil)
			require_Equal(t, rresp.Error.Description, errDesc)
		}
		require_fail(StreamConfig{Name: "fail", MaxBytes: 1024, Storage: FileStorage, Replicas: 6},
			"maximum replicas is 5")
		require_fail(StreamConfig{Name: "fail", MaxBytes: 2 * 1012 * 1024, Storage: FileStorage, Replicas: replica},
			"insufficient storage resources available")
		js, err := nc.JetStream()
		require_NoError(t, err)
		_, err = js.AddStream(&nats.StreamConfig{Name: "stream", MaxBytes: 1024, Storage: nats.FileStorage, Replicas: 1})
		require_NoError(t, err)
		require_fail(StreamConfig{Name: "fail", MaxBytes: 1024, Storage: FileStorage},
			"maximum number of streams reached")
	}

	commonAccSection := `
		no_auth_user: u
		accounts {
			ONE {
				users = [ { user: "u", pass: "s3cr3t!" } ]
				jetstream: {
					max_store: 1Mb
					max_streams: 1
				}
			}
			$SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] }
		}`

	t.Run("clustered", func(t *testing.T) {
		c := createJetStreamClusterWithTemplate(t, `
			listen: 127.0.0.1:-1
			server_name: %s
			jetstream: {
				max_mem_store: 2MB,
				max_file_store: 8MB,
				store_dir: '%s',
			}
			cluster {
				name: %s
				listen: 127.0.0.1:%d
				routes = [%s]
			}`+commonAccSection, "clust", 3)
		defer c.shutdown()
		s := c.randomServer()
		test(t, s, 3)
	})
	t.Run("single", func(t *testing.T) {
		storeDir := t.TempDir()
		conf := createConfFile(t, []byte(fmt.Sprintf(`
			listen: 127.0.0.1:-1
			jetstream: {max_mem_store: 2MB, max_file_store: 8MB, store_dir: '%s'}
			%s`, storeDir, commonAccSection)))
		s, _ := RunServerWithConfig(conf)
		defer s.Shutdown()
		test(t, s, 1)
	})
}

func TestJetStreamLimits(t *testing.T) {
	test := func(t *testing.T, s *Server) {
		nc := natsConnect(t, s.ClientURL())
		defer nc.Close()

		js, err := nc.JetStream()
		require_NoError(t, err)

		si, err := js.AddStream(&nats.StreamConfig{Name: "foo"})
		require_NoError(t, err)
		require_True(t, si.Config.Duplicates == time.Minute)

		si, err = js.AddStream(&nats.StreamConfig{Name: "bar", Duplicates: 1500 * time.Millisecond})
		require_NoError(t, err)
		require_True(t, si.Config.Duplicates == 1500*time.Millisecond)

		_, err = js.UpdateStream(&nats.StreamConfig{Name: "bar", Duplicates: 2 * time.Minute})
		require_Error(t, err)
		require_Equal(t, err.Error(), "nats: duplicates window can not be larger then server limit of 1m0s")

		_, err = js.AddStream(&nats.StreamConfig{Name: "baz", Duplicates: 2 * time.Minute})
		require_Error(t, err)
		require_Equal(t, err.Error(), "nats: duplicates window can not be larger then server limit of 1m0s")

		ci, err := js.AddConsumer("foo", &nats.ConsumerConfig{Durable: "dur1", AckPolicy: nats.AckExplicitPolicy})
		require_NoError(t, err)
		require_True(t, ci.Config.MaxAckPending == 1000)
		require_True(t, ci.Config.MaxRequestBatch == 250)

		_, err = js.AddConsumer("foo", &nats.ConsumerConfig{Durable: "dur2", AckPolicy: nats.AckExplicitPolicy, MaxRequestBatch: 500})
		require_Error(t, err)
		require_Equal(t, err.Error(), "nats: consumer max request batch exceeds server limit of 250")

		ci, err = js.AddConsumer("foo", &nats.ConsumerConfig{Durable: "dur2", AckPolicy: nats.AckExplicitPolicy, MaxAckPending: 500})
		require_NoError(t, err)
		require_True(t, ci.Config.MaxAckPending == 500)
		require_True(t, ci.Config.MaxRequestBatch == 250)

		_, err = js.UpdateConsumer("foo", &nats.ConsumerConfig{Durable: "dur2", AckPolicy: nats.AckExplicitPolicy, MaxAckPending: 2000})
		require_Error(t, err)
		require_Equal(t, err.Error(), "nats: consumer max ack pending exceeds system limit of 1000")

		_, err = js.AddConsumer("foo", &nats.ConsumerConfig{Durable: "dur3", AckPolicy: nats.AckExplicitPolicy, MaxAckPending: 2000})
		require_Error(t, err)
		require_Equal(t, err.Error(), "nats: consumer max ack pending exceeds system limit of 1000")
	}

	t.Run("clustered", func(t *testing.T) {
		tmpl := `
			listen: 127.0.0.1:-1
			server_name: %s
			jetstream: {
				max_mem_store: 2MB,
				max_file_store: 8MB,
				store_dir: '%s',
				limits: {duplicate_window: "1m", max_request_batch: 250}
			}
			cluster {
				name: %s
				listen: 127.0.0.1:%d
				routes = [%s]
			}
			no_auth_user: u
			accounts {
				ONE {
					users = [ { user: "u", pass: "s3cr3t!" } ]
					jetstream: enabled
				}
				$SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] }
			}`
		limitsTest := func(t *testing.T, tmpl string) {
			c := createJetStreamClusterWithTemplate(t, tmpl, "clust", 3)
			defer c.shutdown()
			s := c.randomServer()
			test(t, s)
		}
		// test with max_ack_pending being defined in operator or account
		t.Run("operator", func(t *testing.T) {
			limitsTest(t, strings.Replace(tmpl, "duplicate_window", "max_ack_pending: 1000, duplicate_window", 1))
		})
		t.Run("account", func(t *testing.T) {
			limitsTest(t, strings.Replace(tmpl, "jetstream: enabled", "jetstream: {max_ack_pending: 1000}", 1))
		})
	})

	t.Run("single", func(t *testing.T) {
		tmpl := `
			listen: 127.0.0.1:-1
			jetstream: {
				max_mem_store: 2MB,
				max_file_store: 8MB,
				store_dir: '%s',
				limits: {duplicate_window: "1m", max_request_batch: 250}
			}
			no_auth_user: u
			accounts {
				ONE {
					users = [ { user: "u", pass: "s3cr3t!" } ]
					jetstream: enabled
				}
				$SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] }
			}`
		limitsTest := func(t *testing.T, tmpl string) {
			storeDir := t.TempDir()
			conf := createConfFile(t, []byte(fmt.Sprintf(tmpl, storeDir)))
			s, opts := RunServerWithConfig(conf)
			defer s.Shutdown()
			require_True(t, opts.JetStreamLimits.Duplicates == time.Minute)
			test(t, s)
		}
		// test with max_ack_pending being defined in operator or account
		t.Run("operator", func(t *testing.T) {
			limitsTest(t, strings.Replace(tmpl, "duplicate_window", "max_ack_pending: 1000, duplicate_window", 1))
		})
		t.Run("account", func(t *testing.T) {
			limitsTest(t, strings.Replace(tmpl, "jetstream: enabled", "jetstream: {max_ack_pending: 1000}", 1))
		})
	})
}

func TestJetStreamImportReload(t *testing.T) {
	storeDir := t.TempDir()

	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 2MB, max_file_store: 8MB, store_dir: '%s'}
		accounts: {
			account_a: {
				users: [{user: user_a, password: pwd}]
				exports: [{stream: news.>}]
			}
			account_b: {
				users: [{user: user_b, password: pwd}]
				jetstream: enabled
				imports: [{stream: {subject: news.>, account: account_a}}]
			}
		}`, storeDir)))
	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	ncA := natsConnect(t, s.ClientURL(), nats.UserInfo("user_a", "pwd"))
	defer ncA.Close()

	ncB := natsConnect(t, s.ClientURL(), nats.UserInfo("user_b", "pwd"))
	defer ncB.Close()

	jsB, err := ncB.JetStream()
	require_NoError(t, err)

	_, err = jsB.AddStream(&nats.StreamConfig{Name: "news", Subjects: []string{"news.>"}})
	require_NoError(t, err)

	require_NoError(t, ncA.Publish("news.article", nil))

	checkFor(t, time.Second, 100*time.Millisecond, func() error {
		si, err := jsB.StreamInfo("news")
		if err != nil {
			return err
		}
		if si.State.Msgs != 1 {
			return fmt.Errorf("require uint64 equal, but got: %d != 1", si.State.Msgs)
		}
		return nil
	})

	// Remove exports/imports
	reloadUpdateConfig(t, s, conf, fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 2MB, max_file_store: 8MB, store_dir: '%s'}
		accounts: {
			account_a: {
				users: [{user: user_a, password: pwd}]
			}
			account_b: {
				users: [{user: user_b, password: pwd}]
				jetstream: enabled
			}
		}`, storeDir))

	require_NoError(t, ncA.Publish("news.article", nil))
	require_NoError(t, ncA.Flush())

	si, err := jsB.StreamInfo("news")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 1)
}

func TestJetStreamRecoverSealedAfterServerRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "foo"})
	require_NoError(t, err)

	for i := 0; i < 100; i++ {
		js.PublishAsync("foo", []byte("OK"))
	}
	<-js.PublishAsyncComplete()

	_, err = js.UpdateStream(&nats.StreamConfig{Name: "foo", Sealed: true})
	require_NoError(t, err)

	nc.Close()

	// Stop current
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	// Restart.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	si, err := js.StreamInfo("foo")
	require_NoError(t, err)
	require_True(t, si.State.Msgs == 100)
}

func TestJetStreamImportConsumerStreamSubjectRemapSingle(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 4GB, max_file_store: 1TB, store_dir: %q}
		accounts: {
			JS: {
				jetstream: enabled
				users: [ {user: js, password: pwd} ]
				exports [
					# This is streaming to a delivery subject for a push based consumer.
					{ stream: "deliver.*" }
					{ stream: "foo.*" }
					# This is to ack received messages. This is a service to support sync ack.
					{ service: "$JS.ACK.ORDERS.*.>" }
					# To support ordered consumers, flow control.
					{ service: "$JS.FC.>" }
				]
			},
			IM: {
				users: [ {user: im, password: pwd} ]
				imports [
					{ stream:  { account: JS, subject: "deliver.ORDERS" }, to: "d.*" }
					{ stream:  { account: JS, subject: "foo.*" }, to: "bar.*" }
					{ service: { account: JS, subject: "$JS.FC.>" }}
				]
			},
		}
	`, t.TempDir())))

	test := func(t *testing.T, queue bool) {
		s, _ := RunServerWithConfig(conf)
		defer s.Shutdown()

		nc, js := jsClientConnect(t, s, nats.UserInfo("js", "pwd"))
		defer nc.Close()

		_, err := js.AddStream(&nats.StreamConfig{
			Name:     "ORDERS",
			Subjects: []string{"foo"}, // The JS subject.
			Storage:  nats.MemoryStorage},
		)
		require_NoError(t, err)

		_, err = js.Publish("foo", []byte("OK"))
		require_NoError(t, err)

		queueName := ""
		if queue {
			queueName = "queue"
		}

		_, err = js.AddConsumer("ORDERS", &nats.ConsumerConfig{
			DeliverSubject: "deliver.ORDERS",
			AckPolicy:      nats.AckExplicitPolicy,
			DeliverGroup:   queueName,
		})
		require_NoError(t, err)

		nc2, err := nats.Connect(s.ClientURL(), nats.UserInfo("im", "pwd"))
		require_NoError(t, err)
		defer nc2.Close()

		var sub *nats.Subscription
		if queue {
			sub, err = nc2.QueueSubscribeSync("d.ORDERS", queueName)
			require_NoError(t, err)
		} else {
			sub, err = nc2.SubscribeSync("d.ORDERS")
			require_NoError(t, err)
		}

		m, err := sub.NextMsg(time.Second)
		require_NoError(t, err)

		if m.Subject != "foo" {
			t.Fatalf("Subject not mapped correctly across account boundary, expected %q got %q", "foo", m.Subject)
		}

		// Now do one that would kick in a transform.
		_, err = js.AddConsumer("ORDERS", &nats.ConsumerConfig{
			DeliverSubject: "foo.ORDERS",
			AckPolicy:      nats.AckExplicitPolicy,
			DeliverGroup:   queueName,
		})
		require_NoError(t, err)

		if queue {
			sub, err = nc2.QueueSubscribeSync("bar.ORDERS", queueName)
			require_NoError(t, err)
		} else {
			sub, err = nc2.SubscribeSync("bar.ORDERS")
			require_NoError(t, err)
		}
		m, err = sub.NextMsg(time.Second)
		require_NoError(t, err)

		if m.Subject != "foo" {
			t.Fatalf("Subject not mapped correctly across account boundary, expected %q got %q", "foo", m.Subject)
		}
	}

	t.Run("noqueue", func(t *testing.T) {
		test(t, false)
	})
	t.Run("queue", func(t *testing.T) {
		test(t, true)
	})
}

func TestJetStreamWorkQueueSourceRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	sent := 10
	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "FOO",
		Replicas: 1,
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	for i := 0; i < sent; i++ {
		_, err = js.Publish("foo", nil)
		require_NoError(t, err)
	}

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Replicas: 1,
		// TODO test will pass when retention commented out
		Retention: nats.WorkQueuePolicy,
		Sources:   []*nats.StreamSource{{Name: "FOO"}}})
	require_NoError(t, err)

	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{Durable: "dur", AckPolicy: nats.AckExplicitPolicy})
	require_NoError(t, err)

	sub, err := js.PullSubscribe("foo", "dur", nats.BindStream("TEST"))
	require_NoError(t, err)

	time.Sleep(1 * time.Second)

	ci, err := js.ConsumerInfo("TEST", "dur")
	require_NoError(t, err)
	require_True(t, ci.NumPending == uint64(sent))

	msgs, err := sub.Fetch(sent)
	require_NoError(t, err)
	require_True(t, len(msgs) == sent)

	for i := 0; i < sent; i++ {
		err = msgs[i].AckSync()
		require_NoError(t, err)
	}

	ci, err = js.ConsumerInfo("TEST", "dur")
	require_NoError(t, err)
	require_True(t, ci.NumPending == 0)

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_True(t, si.State.Msgs == 0)

	// Restart server
	nc.Close()
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	time.Sleep(200 * time.Millisecond)
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	checkFor(t, 10*time.Second, 200*time.Millisecond, func() error {
		hs := s.healthz(nil)
		if hs.Status == "ok" && hs.Error == _EMPTY_ {
			return nil
		}
		return fmt.Errorf("healthz %s %s", hs.Error, hs.Status)
	})

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)

	if si.State.Msgs != 0 {
		t.Fatalf("Expected 0 messages on restart, got %d", si.State.Msgs)
	}

	ctest, err := js.ConsumerInfo("TEST", "dur")
	require_NoError(t, err)

	//TODO (mh) I have experienced in other tests that NumPending has a value of 1 post restart.
	// seems to go awary in single server setup. It's also unrelated to work queue
	// but that error seems benign.
	if ctest.NumPending != 0 {
		t.Fatalf("Expected pending of 0 but got %d", ctest.NumPending)
	}

	sub, err = js.PullSubscribe("foo", "dur", nats.BindStream("TEST"))
	require_NoError(t, err)
	_, err = sub.Fetch(1, nats.MaxWait(time.Second))
	if err != nats.ErrTimeout {
		require_NoError(t, err)
	}
}

func TestJetStreamWorkQueueSourceNamingRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "C1", Subjects: []string{"foo.*"}})
	require_NoError(t, err)
	_, err = js.AddStream(&nats.StreamConfig{Name: "C2", Subjects: []string{"bar.*"}})
	require_NoError(t, err)

	sendCount := 10
	for i := 0; i < sendCount; i++ {
		_, err = js.Publish(fmt.Sprintf("foo.%d", i), nil)
		require_NoError(t, err)
		_, err = js.Publish(fmt.Sprintf("bar.%d", i), nil)
		require_NoError(t, err)
	}

	// TODO Test will always pass if pending is 0
	pending := 1
	// For some yet unknown reason this failure seems to require 2 streams to source from.
	// This might possibly be timing, as the test sometimes passes
	streams := 2
	totalPending := uint64(streams * pending)
	totalMsgs := streams * sendCount
	totalNonPending := streams * (sendCount - pending)

	// TODO Test will always pass if this is named A (go returns directory names sorted)
	// A: this stream is recovered BEFORE C1/C2, tbh, I'd expect this to be the case to fail, but it isn't
	// D: this stream is recovered AFTER C1/C2, which is the case that fails (perhaps it is timing)
	srcName := "D"
	_, err = js.AddStream(&nats.StreamConfig{
		Name:      srcName,
		Retention: nats.WorkQueuePolicy,
		Sources:   []*nats.StreamSource{{Name: "C1"}, {Name: "C2"}},
	})
	require_NoError(t, err)

	// Add a consumer and consume all but totalPending messages
	_, err = js.AddConsumer(srcName, &nats.ConsumerConfig{Durable: "dur", AckPolicy: nats.AckExplicitPolicy})
	require_NoError(t, err)

	sub, err := js.PullSubscribe("", "dur", nats.BindStream(srcName))
	require_NoError(t, err)

	checkFor(t, 5*time.Second, time.Millisecond*200, func() error {
		if ci, err := js.ConsumerInfo(srcName, "dur"); err != nil {
			return err
		} else if ci.NumPending != uint64(totalMsgs) {
			return fmt.Errorf("not enough messages: %d", ci.NumPending)
		}
		return nil
	})

	// consume all but messages we want pending
	msgs, err := sub.Fetch(totalNonPending)
	require_NoError(t, err)
	require_True(t, len(msgs) == totalNonPending)

	for _, m := range msgs {
		err = m.AckSync()
		require_NoError(t, err)
	}

	ci, err := js.ConsumerInfo(srcName, "dur")
	require_NoError(t, err)
	require_True(t, ci.NumPending == totalPending)

	si, err := js.StreamInfo(srcName)
	require_NoError(t, err)
	require_True(t, si.State.Msgs == totalPending)

	// Restart server
	nc.Close()
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	time.Sleep(200 * time.Millisecond)
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	checkFor(t, 10*time.Second, 200*time.Millisecond, func() error {
		hs := s.healthz(nil)
		if hs.Status == "ok" && hs.Error == _EMPTY_ {
			return nil
		}
		return fmt.Errorf("healthz %s %s", hs.Error, hs.Status)
	})

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	si, err = js.StreamInfo(srcName)
	require_NoError(t, err)

	if si.State.Msgs != totalPending {
		t.Fatalf("Expected 0 messages on restart, got %d", si.State.Msgs)
	}
}

func TestJetStreamDisabledHealthz(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	if !s.JetStreamEnabled() {
		t.Fatalf("Expected JetStream to be enabled")
	}

	s.DisableJetStream()

	hs := s.healthz(&HealthzOptions{JSEnabledOnly: true})
	if hs.Status == "unavailable" && hs.Error == NewJSNotEnabledError().Error() {
		return
	}

	t.Fatalf("Expected healthz to return error if JetStream is disabled, got status: %s", hs.Status)
}

func TestJetStreamStreamRepublishCycle(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, _ := jsClientConnect(t, s)
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:     "RPC",
		Storage:  MemoryStorage,
		Subjects: []string{"foo.>", "bar.*", "baz"},
	}

	expectFail := func() {
		t.Helper()
		req, err := json.Marshal(cfg)
		require_NoError(t, err)
		rmsg, err := nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
		require_NoError(t, err)
		var resp JSApiStreamCreateResponse
		err = json.Unmarshal(rmsg.Data, &resp)
		require_NoError(t, err)
		if resp.Type != JSApiStreamCreateResponseType {
			t.Fatalf("Invalid response type %s expected %s", resp.Type, JSApiStreamCreateResponseType)
		}
		if resp.Error == nil {
			t.Fatalf("Expected error but got none")
		}
		if !strings.Contains(resp.Error.Description, "republish destination forms a cycle") {
			t.Fatalf("Expected cycle error, got %q", resp.Error.Description)
		}
	}

	cfg.RePublish = &RePublish{
		Source:      "foo.>",
		Destination: "foo.>",
	}
	expectFail()

	cfg.RePublish = &RePublish{
		Source:      "bar.bar",
		Destination: "foo.bar",
	}
	expectFail()

	cfg.RePublish = &RePublish{
		Source:      "baz",
		Destination: "bar.bar",
	}
	expectFail()
}

func TestJetStreamStreamRepublishOneTokenMatch(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:     "Stream1",
		Storage:  MemoryStorage,
		Subjects: []string{"one", "four"},
		RePublish: &RePublish{
			Source:      "one",
			Destination: "uno",
			HeadersOnly: false,
		},
	}
	addStream(t, nc, cfg)

	sub, err := nc.SubscribeSync("uno")
	require_NoError(t, err)

	msg, toSend := bytes.Repeat([]byte("Z"), 512), 100
	for i := 0; i < toSend; i++ {
		js.PublishAsync("one", msg)
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	checkSubsPending(t, sub, toSend)
	m, err := sub.NextMsg(time.Second)
	require_NoError(t, err)

	if !(len(m.Data) > 0) {
		t.Fatalf("Expected msg data")
	}
}

func TestJetStreamStreamRepublishMultiTokenMatch(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:     "Stream1",
		Storage:  MemoryStorage,
		Subjects: []string{"one.>", "four.>"},
		RePublish: &RePublish{
			Source:      "one.two.>",
			Destination: "uno.dos.>",
			HeadersOnly: false,
		},
	}
	addStream(t, nc, cfg)

	sub, err := nc.SubscribeSync("uno.dos.>")
	require_NoError(t, err)

	msg, toSend := bytes.Repeat([]byte("Z"), 512), 100
	for i := 0; i < toSend; i++ {
		js.PublishAsync("one.two.three", msg)
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	checkSubsPending(t, sub, toSend)
	m, err := sub.NextMsg(time.Second)
	require_NoError(t, err)

	if !(len(m.Data) > 0) {
		t.Fatalf("Expected msg data")
	}
}

func TestJetStreamStreamRepublishAnySubjectMatch(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:     "Stream1",
		Storage:  MemoryStorage,
		Subjects: []string{"one.>", "four.>"},
		RePublish: &RePublish{
			Destination: "uno.dos.>",
			HeadersOnly: false,
		},
	}
	addStream(t, nc, cfg)

	sub, err := nc.SubscribeSync("uno.dos.>")
	require_NoError(t, err)

	msg, toSend := bytes.Repeat([]byte("Z"), 512), 100
	for i := 0; i < toSend; i++ {
		js.PublishAsync("one.two.three", msg)
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	checkSubsPending(t, sub, toSend)
	m, err := sub.NextMsg(time.Second)
	require_NoError(t, err)

	if !(len(m.Data) > 0) {
		t.Fatalf("Expected msg data")
	}
}

func TestJetStreamStreamRepublishMultiTokenNoMatch(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:     "Stream1",
		Storage:  MemoryStorage,
		Subjects: []string{"one.>", "four.>"},
		RePublish: &RePublish{
			Source:      "one.two.>",
			Destination: "uno.dos.>",
			HeadersOnly: true,
		},
	}
	addStream(t, nc, cfg)

	sub, err := nc.SubscribeSync("uno.dos.>")
	require_NoError(t, err)

	msg, toSend := bytes.Repeat([]byte("Z"), 512), 100
	for i := 0; i < toSend; i++ {
		js.PublishAsync("four.five.six", msg)
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	checkSubsPending(t, sub, 0)
	require_NoError(t, err)
}

func TestJetStreamStreamRepublishOneTokenNoMatch(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:     "Stream1",
		Storage:  MemoryStorage,
		Subjects: []string{"one", "four"},
		RePublish: &RePublish{
			Source:      "one",
			Destination: "uno",
			HeadersOnly: true,
		},
	}
	addStream(t, nc, cfg)

	sub, err := nc.SubscribeSync("uno")
	require_NoError(t, err)

	msg, toSend := bytes.Repeat([]byte("Z"), 512), 100
	for i := 0; i < toSend; i++ {
		js.PublishAsync("four", msg)
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	checkSubsPending(t, sub, 0)
	require_NoError(t, err)
}

func TestJetStreamStreamRepublishHeadersOnly(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:     "RPC",
		Storage:  MemoryStorage,
		Subjects: []string{"foo", "bar", "baz"},
		RePublish: &RePublish{
			Destination: "RP.>",
			HeadersOnly: true,
		},
	}
	addStream(t, nc, cfg)

	sub, err := nc.SubscribeSync("RP.>")
	require_NoError(t, err)

	msg, toSend := bytes.Repeat([]byte("Z"), 512), 100
	for i := 0; i < toSend; i++ {
		js.PublishAsync("foo", msg)
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	checkSubsPending(t, sub, toSend)
	last := "0"
	for i := 0; i < toSend; i++ {
		m, err := sub.NextMsg(time.Second)
		require_NoError(t, err)

		if len(m.Data) > 0 {
			t.Fatalf("Expected no msg just headers, but got %d bytes", len(m.Data))
		}
		if sz := m.Header.Get(JSMsgSize); sz != "512" {
			t.Fatalf("Expected msg size hdr, got %q", sz)
		}
		if lastHeader := m.Header.Get(JSLastSequence); lastHeader != last {
			t.Fatalf("Expected last message header %q, got %q", last, lastHeader)
		}
		last = m.Header.Get(JSSequence)
	}
}

func TestJetStreamMsgGetNoAdvisory(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "foo"})
	require_NoError(t, err)

	for i := 0; i < 100; i++ {
		js.PublishAsync("foo", []byte("ok"))
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	sub, err := nc.SubscribeSync("$JS.EVENT.ADVISORY.>")
	require_NoError(t, err)

	_, err = js.GetMsg("foo", 1)
	require_NoError(t, err)

	checkSubsPending(t, sub, 0)
}

func TestJetStreamDirectMsgGet(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, _ := jsClientConnect(t, s)
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:        "DSMG",
		Storage:     MemoryStorage,
		Subjects:    []string{"foo", "bar", "baz"},
		MaxMsgsPer:  1,
		AllowDirect: true,
	}
	addStream(t, nc, cfg)

	sendStreamMsg(t, nc, "foo", "foo")
	sendStreamMsg(t, nc, "bar", "bar")
	sendStreamMsg(t, nc, "baz", "baz")

	getSubj := fmt.Sprintf(JSDirectMsgGetT, "DSMG")
	getMsg := func(req *JSApiMsgGetRequest) *nats.Msg {
		var b []byte
		var err error
		if req != nil {
			b, err = json.Marshal(req)
			require_NoError(t, err)
		}
		m, err := nc.Request(getSubj, b, time.Second)
		require_NoError(t, err)
		return m
	}

	m := getMsg(&JSApiMsgGetRequest{LastFor: "foo"})
	require_True(t, string(m.Data) == "foo")
	require_True(t, m.Header.Get(JSStream) == "DSMG")
	require_True(t, m.Header.Get(JSSequence) == "1")
	require_True(t, m.Header.Get(JSSubject) == "foo")
	require_True(t, m.Subject != "foo")
	require_True(t, m.Header.Get(JSTimeStamp) != _EMPTY_)

	m = getMsg(&JSApiMsgGetRequest{LastFor: "bar"})
	require_True(t, string(m.Data) == "bar")
	require_True(t, m.Header.Get(JSStream) == "DSMG")
	require_True(t, m.Header.Get(JSSequence) == "2")
	require_True(t, m.Header.Get(JSSubject) == "bar")
	require_True(t, m.Subject != "bar")
	require_True(t, m.Header.Get(JSTimeStamp) != _EMPTY_)

	m = getMsg(&JSApiMsgGetRequest{LastFor: "baz"})
	require_True(t, string(m.Data) == "baz")
	require_True(t, m.Header.Get(JSStream) == "DSMG")
	require_True(t, m.Header.Get(JSSequence) == "3")
	require_True(t, m.Header.Get(JSSubject) == "baz")
	require_True(t, m.Subject != "baz")
	require_True(t, m.Header.Get(JSTimeStamp) != _EMPTY_)

	// Test error conditions

	// Nil request
	m = getMsg(nil)
	require_True(t, len(m.Data) == 0)
	require_True(t, m.Header.Get("Status") == "408")
	require_True(t, m.Header.Get("Description") == "Empty Request")

	// Empty request
	m = getMsg(&JSApiMsgGetRequest{})
	require_True(t, len(m.Data) == 0)
	require_True(t, m.Header.Get("Status") == "408")
	require_True(t, m.Header.Get("Description") == "Empty Request")

	// Both set
	m = getMsg(&JSApiMsgGetRequest{Seq: 1, LastFor: "foo"})
	require_True(t, len(m.Data) == 0)
	require_True(t, m.Header.Get("Status") == "408")
	require_True(t, m.Header.Get("Description") == "Bad Request")

	// Not found
	m = getMsg(&JSApiMsgGetRequest{LastFor: "foobar"})
	require_True(t, len(m.Data) == 0)
	require_True(t, m.Header.Get("Status") == "404")
	require_True(t, m.Header.Get("Description") == "Message Not Found")

	m = getMsg(&JSApiMsgGetRequest{Seq: 22})
	require_True(t, len(m.Data) == 0)
	require_True(t, m.Header.Get("Status") == "404")
	require_True(t, m.Header.Get("Description") == "Message Not Found")
}

// This allows support for a get next given a sequence as a starting.
// This allows these to be chained together if needed for sparse streams.
func TestJetStreamDirectMsgGetNext(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, _ := jsClientConnect(t, s)
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:        "DSMG",
		Storage:     MemoryStorage,
		Subjects:    []string{"foo", "bar", "baz"},
		AllowDirect: true,
	}
	addStream(t, nc, cfg)

	sendStreamMsg(t, nc, "foo", "foo")
	for i := 0; i < 10; i++ {
		sendStreamMsg(t, nc, "bar", "bar")
	}
	for i := 0; i < 10; i++ {
		sendStreamMsg(t, nc, "baz", "baz")
	}
	sendStreamMsg(t, nc, "foo", "foo")

	getSubj := fmt.Sprintf(JSDirectMsgGetT, "DSMG")
	getMsg := func(seq uint64, subj string) *nats.Msg {
		req := []byte(fmt.Sprintf(`{"seq": %d, "next_by_subj": %q}`, seq, subj))
		m, err := nc.Request(getSubj, req, time.Second)
		require_NoError(t, err)
		return m
	}

	m := getMsg(0, "foo")
	require_True(t, m.Header.Get(JSSequence) == "1")
	require_True(t, m.Header.Get(JSSubject) == "foo")

	m = getMsg(1, "foo")
	require_True(t, m.Header.Get(JSSequence) == "1")
	require_True(t, m.Header.Get(JSSubject) == "foo")

	m = getMsg(2, "foo")
	require_True(t, m.Header.Get(JSSequence) == "22")
	require_True(t, m.Header.Get(JSSubject) == "foo")

	m = getMsg(2, "bar")
	require_True(t, m.Header.Get(JSSequence) == "2")
	require_True(t, m.Header.Get(JSSubject) == "bar")

	m = getMsg(5, "baz")
	require_True(t, m.Header.Get(JSSequence) == "12")
	require_True(t, m.Header.Get(JSSubject) == "baz")

	m = getMsg(14, "baz")
	require_True(t, m.Header.Get(JSSequence) == "14")
	require_True(t, m.Header.Get(JSSubject) == "baz")
}

///////////////////////////////////////////////////////////////////////////
// Simple JetStream Benchmarks
///////////////////////////////////////////////////////////////////////////

func Benchmark__JetStreamPubWithAck(b *testing.B) {
	s := RunBasicJetStreamServer(b)
	defer s.Shutdown()

	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: "foo"})
	if err != nil {
		b.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc, err := nats.Connect(s.ClientURL())
	if err != nil {
		b.Fatalf("Failed to create client: %v", err)
	}
	defer nc.Close()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		nc.Request("foo", []byte("Hello World!"), 50*time.Millisecond)
	}
	b.StopTimer()

	state := mset.state()
	if int(state.Msgs) != b.N {
		b.Fatalf("Expected %d messages, got %d", b.N, state.Msgs)
	}
}

func Benchmark____JetStreamPubNoAck(b *testing.B) {
	s := RunBasicJetStreamServer(b)
	defer s.Shutdown()

	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: "foo"})
	if err != nil {
		b.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc, err := nats.Connect(s.ClientURL())
	if err != nil {
		b.Fatalf("Failed to create client: %v", err)
	}
	defer nc.Close()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := nc.Publish("foo", []byte("Hello World!")); err != nil {
			b.Fatalf("Unexpected error: %v", err)
		}
	}
	nc.Flush()
	b.StopTimer()

	state := mset.state()
	if int(state.Msgs) != b.N {
		b.Fatalf("Expected %d messages, got %d", b.N, state.Msgs)
	}
}

func Benchmark_JetStreamPubAsyncAck(b *testing.B) {
	s := RunBasicJetStreamServer(b)
	defer s.Shutdown()

	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: "foo"})
	if err != nil {
		b.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc, err := nats.Connect(s.ClientURL(), nats.NoReconnect())
	if err != nil {
		b.Fatalf("Failed to create client: %v", err)
	}
	defer nc.Close()

	// Put ack stream on its own connection.
	anc, err := nats.Connect(s.ClientURL())
	if err != nil {
		b.Fatalf("Failed to create client: %v", err)
	}
	defer anc.Close()

	acks := nats.NewInbox()
	sub, _ := anc.Subscribe(acks, func(m *nats.Msg) {
		// Just eat them for this test.
	})
	// set max pending to unlimited.
	sub.SetPendingLimits(-1, -1)
	defer sub.Unsubscribe()

	anc.Flush()
	runtime.GC()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := nc.PublishRequest("foo", acks, []byte("Hello World!")); err != nil {
			b.Fatalf("[%d] Unexpected error: %v", i, err)
		}
	}
	nc.Flush()
	b.StopTimer()

	state := mset.state()
	if int(state.Msgs) != b.N {
		b.Fatalf("Expected %d messages, got %d", b.N, state.Msgs)
	}
}

func Benchmark____JetStreamSubNoAck(b *testing.B) {
	if b.N < 10000 {
		return
	}

	s := RunBasicJetStreamServer(b)
	defer s.Shutdown()

	mname := "foo"
	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: mname})
	if err != nil {
		b.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc, err := nats.Connect(s.ClientURL(), nats.NoReconnect())
	if err != nil {
		b.Fatalf("Failed to create client: %v", err)
	}
	defer nc.Close()

	// Queue up messages.
	for i := 0; i < b.N; i++ {
		nc.Publish(mname, []byte("Hello World!"))
	}
	nc.Flush()

	state := mset.state()
	if state.Msgs != uint64(b.N) {
		b.Fatalf("Expected %d messages, got %d", b.N, state.Msgs)
	}

	total := int32(b.N)
	received := int32(0)
	done := make(chan bool)

	deliverTo := "DM"
	oname := "O"

	nc.Subscribe(deliverTo, func(m *nats.Msg) {
		// We only are done when we receive all, we could check for gaps too.
		if atomic.AddInt32(&received, 1) >= total {
			done <- true
		}
	})
	nc.Flush()

	b.ResetTimer()
	o, err := mset.addConsumer(&ConsumerConfig{DeliverSubject: deliverTo, Durable: oname, AckPolicy: AckNone})
	if err != nil {
		b.Fatalf("Expected no error with registered interest, got %v", err)
	}
	defer o.delete()
	<-done
	b.StopTimer()
}

func benchJetStreamWorkersAndBatch(b *testing.B, numWorkers, batchSize int) {
	// Avoid running at too low of numbers since that chews up memory and GC.
	if b.N < numWorkers*batchSize {
		return
	}

	s := RunBasicJetStreamServer(b)
	defer s.Shutdown()

	mname := "MSET22"
	mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: mname})
	if err != nil {
		b.Fatalf("Unexpected error adding stream: %v", err)
	}
	defer mset.delete()

	nc, err := nats.Connect(s.ClientURL(), nats.NoReconnect())
	if err != nil {
		b.Fatalf("Failed to create client: %v", err)
	}
	defer nc.Close()

	// Queue up messages.
	for i := 0; i < b.N; i++ {
		nc.Publish(mname, []byte("Hello World!"))
	}
	nc.Flush()

	state := mset.state()
	if state.Msgs != uint64(b.N) {
		b.Fatalf("Expected %d messages, got %d", b.N, state.Msgs)
	}

	// Create basic work queue mode consumer.
	oname := "WQ"
	o, err := mset.addConsumer(&ConsumerConfig{Durable: oname, AckPolicy: AckExplicit})
	if err != nil {
		b.Fatalf("Expected no error with registered interest, got %v", err)
	}
	defer o.delete()

	total := int32(b.N)
	received := int32(0)
	start := make(chan bool)
	done := make(chan bool)

	batchSizeMsg := []byte(strconv.Itoa(batchSize))
	reqNextMsgSubj := o.requestNextMsgSubject()

	for i := 0; i < numWorkers; i++ {
		nc, err := nats.Connect(s.ClientURL(), nats.NoReconnect())
		if err != nil {
			b.Fatalf("Failed to create client: %v", err)
		}
		defer nc.Close()

		deliverTo := nats.NewInbox()
		nc.Subscribe(deliverTo, func(m *nats.Msg) {
			if atomic.AddInt32(&received, 1) >= total {
				done <- true
			}
			// Ack + Next request.
			nc.PublishRequest(m.Reply, deliverTo, AckNext)
		})
		nc.Flush()
		go func() {
			<-start
			nc.PublishRequest(reqNextMsgSubj, deliverTo, batchSizeMsg)
		}()
	}

	b.ResetTimer()
	close(start)
	<-done
	b.StopTimer()
}

func Benchmark___JetStream1x1Worker(b *testing.B) {
	benchJetStreamWorkersAndBatch(b, 1, 1)
}

func Benchmark__JetStream1x1kWorker(b *testing.B) {
	benchJetStreamWorkersAndBatch(b, 1, 1024)
}

func Benchmark_JetStream10x1kWorker(b *testing.B) {
	benchJetStreamWorkersAndBatch(b, 10, 1024)
}

func Benchmark_JetStream4x512Worker(b *testing.B) {
	benchJetStreamWorkersAndBatch(b, 4, 512)
}

func TestJetStreamKVMemoryStorePerf(t *testing.T) {
	// Comment out to run, holding place for now.
	t.SkipNow()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	kv, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: "TEST", History: 1, Storage: nats.MemoryStorage})
	require_NoError(t, err)

	start := time.Now()
	for i := 0; i < 100_000; i++ {
		_, err := kv.PutString(fmt.Sprintf("foo.%d", i), "HELLO")
		require_NoError(t, err)
	}
	fmt.Printf("Took %v for first run\n", time.Since(start))

	start = time.Now()
	for i := 0; i < 100_000; i++ {
		_, err := kv.PutString(fmt.Sprintf("foo.%d", i), "HELLO WORLD")
		require_NoError(t, err)
	}
	fmt.Printf("Took %v for second run\n", time.Since(start))

	start = time.Now()
	for i := 0; i < 100_000; i++ {
		_, err := kv.Get(fmt.Sprintf("foo.%d", i))
		require_NoError(t, err)
	}
	fmt.Printf("Took %v for get\n", time.Since(start))
}

func TestJetStreamKVMemoryStoreDirectGetPerf(t *testing.T) {
	// Comment out to run, holding place for now.
	t.SkipNow()

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	cfg := &StreamConfig{
		Name:        "TEST",
		Storage:     MemoryStorage,
		Subjects:    []string{"foo.*"},
		MaxMsgsPer:  1,
		AllowDirect: true,
	}
	addStream(t, nc, cfg)

	start := time.Now()
	for i := 0; i < 100_000; i++ {
		_, err := js.Publish(fmt.Sprintf("foo.%d", i), []byte("HELLO"))
		require_NoError(t, err)
	}
	fmt.Printf("Took %v for put\n", time.Since(start))

	getSubj := fmt.Sprintf(JSDirectMsgGetT, "TEST")

	const tmpl = "{\"last_by_subj\":%q}"

	start = time.Now()
	for i := 0; i < 100_000; i++ {
		req := []byte(fmt.Sprintf(tmpl, fmt.Sprintf("foo.%d", i)))
		_, err := nc.Request(getSubj, req, time.Second)
		require_NoError(t, err)
	}
	fmt.Printf("Took %v for get\n", time.Since(start))
}

func TestJetStreamMultiplePullPerf(t *testing.T) {
	skip(t)

	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	js.AddStream(&nats.StreamConfig{Name: "mp22", Storage: nats.FileStorage})
	defer js.DeleteStream("mp22")

	n, msg := 1_000_000, []byte("OK")
	for i := 0; i < n; i++ {
		js.PublishAsync("mp22", msg)
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(10 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	si, err := js.StreamInfo("mp22")
	require_NoError(t, err)

	fmt.Printf("msgs: %d, total_bytes: %v\n", si.State.Msgs, friendlyBytes(int64(si.State.Bytes)))

	// 10 pull subscribers each asking for 100 msgs.
	_, err = js.AddConsumer("mp22", &nats.ConsumerConfig{
		Durable:       "d",
		MaxAckPending: 8_000,
		AckPolicy:     nats.AckExplicitPolicy,
	})
	require_NoError(t, err)

	startCh := make(chan bool)
	var wg sync.WaitGroup

	np, bs := 10, 100

	count := 0

	for i := 0; i < np; i++ {
		nc, js := jsClientConnect(t, s)
		defer nc.Close()
		sub, err := js.PullSubscribe("mp22", "d")
		require_NoError(t, err)

		wg.Add(1)
		go func(sub *nats.Subscription) {
			defer wg.Done()
			<-startCh
			for i := 0; i < n/(np*bs); i++ {
				msgs, err := sub.Fetch(bs)
				if err != nil {
					t.Logf("Got error on pull: %v", err)
					return
				}
				if len(msgs) != bs {
					t.Logf("Expected %d msgs, got %d", bs, len(msgs))
					return
				}
				count += len(msgs)
				for _, m := range msgs {
					m.Ack()
				}
			}
		}(sub)
	}

	start := time.Now()
	close(startCh)
	wg.Wait()

	tt := time.Since(start)
	fmt.Printf("Took %v to receive %d msgs [%d]\n", tt, n, count)
	fmt.Printf("%.0f msgs/s\n", float64(n)/tt.Seconds())
	fmt.Printf("%.0f mb/s\n\n", float64(si.State.Bytes/(1024*1024))/tt.Seconds())
}

func TestJetStreamMirrorUpdatesNotSupported(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "SOURCE"})
	require_NoError(t, err)

	cfg := &nats.StreamConfig{
		Name:   "M",
		Mirror: &nats.StreamSource{Name: "SOURCE"},
	}
	_, err = js.AddStream(cfg)
	require_NoError(t, err)

	// Promoting a mirror is supported though.
	cfg.Mirror = nil
	_, err = js.UpdateStream(cfg)
	require_NoError(t, err)
}

func TestJetStreamMirrorFirstSeqNotSupported(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	_, err := s.gacc.addStream(&StreamConfig{Name: "SOURCE"})
	require_NoError(t, err)

	cfg := &StreamConfig{
		Name:     "M",
		Mirror:   &StreamSource{Name: "SOURCE"},
		FirstSeq: 123,
	}
	_, err = s.gacc.addStream(cfg)
	require_Error(t, err, NewJSMirrorWithFirstSeqError())
}

func TestJetStreamDirectGetBySubject(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q}

		ONLYME = {
			publish = { allow = "$JS.API.DIRECT.GET.KV.vid.22.>"}
		}

		accounts: {
			A: {
				jetstream: enabled
				users: [
					{ user: admin, password: s3cr3t },
					{ user: user, password: pwd, permissions: $ONLYME},
				]
			},
		}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s, nats.UserInfo("admin", "s3cr3t"))
	defer nc.Close()

	// Do by hand for now.
	cfg := &StreamConfig{
		Name:        "KV",
		Storage:     MemoryStorage,
		Subjects:    []string{"vid.*.>"},
		MaxMsgsPer:  1,
		AllowDirect: true,
	}
	addStream(t, nc, cfg)

	// Add in mirror as well.
	cfg = &StreamConfig{
		Name:         "M",
		Storage:      MemoryStorage,
		Mirror:       &StreamSource{Name: "KV"},
		MirrorDirect: true,
	}
	addStream(t, nc, cfg)

	v22 := "vid.22.speed"
	v33 := "vid.33.speed"
	_, err := js.Publish(v22, []byte("100"))
	require_NoError(t, err)
	_, err = js.Publish(v33, []byte("55"))
	require_NoError(t, err)

	// User the restricted user.
	nc, _ = jsClientConnect(t, s, nats.UserInfo("user", "pwd"))
	defer nc.Close()

	errCh := make(chan error, 10)
	nc.SetErrorHandler(func(_ *nats.Conn, _ *nats.Subscription, e error) {
		select {
		case errCh <- e:
		default:
		}
	})

	getSubj := fmt.Sprintf(JSDirectGetLastBySubjectT, "KV", v22)
	m, err := nc.Request(getSubj, nil, time.Second)
	require_NoError(t, err)
	require_True(t, string(m.Data) == "100")

	// Now attempt to access vid 33 data..
	getSubj = fmt.Sprintf(JSDirectGetLastBySubjectT, "KV", v33)
	_, err = nc.Request(getSubj, nil, 200*time.Millisecond)
	require_Error(t, err) // timeout here.

	select {
	case e := <-errCh:
		if !strings.HasPrefix(e.Error(), "nats: permissions violation") {
			t.Fatalf("Expected a permissions violation but got %v", e)
		}
	case <-time.After(time.Second):
		t.Fatalf("Expected to get a permissions error, got none")
	}

	// Now make sure mirrors are doing right thing with new way as well.
	var sawMirror bool
	getSubj = fmt.Sprintf(JSDirectGetLastBySubjectT, "KV", v22)
	for i := 0; i < 100; i++ {
		m, err := nc.Request(getSubj, nil, time.Second)
		require_NoError(t, err)
		if shdr := m.Header.Get(JSStream); shdr == "M" {
			sawMirror = true
			break
		}
	}
	if !sawMirror {
		t.Fatalf("Expected to see the mirror respond at least once")
	}
}

func TestJetStreamProperErrorDueToOverlapSubjects(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	c := createJetStreamClusterExplicit(t, "R3S", 3)
	defer c.shutdown()

	test := func(t *testing.T, s *Server) {
		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		_, err := js.AddStream(&nats.StreamConfig{
			Name:     "TEST",
			Subjects: []string{"foo.*"},
		})
		require_NoError(t, err)

		// Now do this by end since we want to check the error returned.
		sc := &nats.StreamConfig{
			Name:     "TEST2",
			Subjects: []string{"foo.>"},
		}
		req, _ := json.Marshal(sc)
		msg, err := nc.Request(fmt.Sprintf(JSApiStreamCreateT, sc.Name), req, time.Second)
		require_NoError(t, err)

		var scResp JSApiStreamCreateResponse
		err = json.Unmarshal(msg.Data, &scResp)
		require_NoError(t, err)

		if scResp.Error == nil || !IsNatsErr(scResp.Error, JSStreamSubjectOverlapErr) {
			t.Fatalf("Did not receive correct error: %+v", scResp)
		}
	}

	t.Run("standalone", func(t *testing.T) { test(t, s) })
	t.Run("clustered", func(t *testing.T) { test(t, c.randomServer()) })
}

func TestJetStreamServerCipherConvert(t *testing.T) {
	tmpl := `
		server_name: S22
		listen: 127.0.0.1:-1
		jetstream: {key: s3cr3t, store_dir: '%s', cipher: %s}
	`
	storeDir := t.TempDir()

	// Create a stream and a consumer under one cipher, and restart the server with a new cipher.
	conf := createConfFile(t, []byte(fmt.Sprintf(tmpl, storeDir, "AES")))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	// Client based API
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	cfg := &nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	}
	if _, err := js.AddStream(cfg); err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	for i := 0; i < 1000; i++ {
		msg := []byte(fmt.Sprintf("TOP SECRET DOCUMENT #%d", i+1))
		_, err := js.Publish("foo", msg)
		require_NoError(t, err)
	}

	// Make sure consumers convert as well.
	sub, err := js.PullSubscribe("foo", "dlc")
	require_NoError(t, err)
	for _, m := range fetchMsgs(t, sub, 100, 5*time.Second) {
		m.AckSync()
	}

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)

	ci, err := js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)

	// Stop current
	s.Shutdown()

	conf = createConfFile(t, []byte(fmt.Sprintf(tmpl, storeDir, "ChaCha")))

	s, _ = RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	si2, err := js.StreamInfo("TEST")
	require_NoError(t, err)

	if !reflect.DeepEqual(si, si2) {
		t.Fatalf("Stream infos did not match\n%+v\nvs\n%+v", si, si2)
	}

	ci2, err := js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)

	// Consumer create times can be slightly off after restore from disk.
	now := time.Now()
	ci.Created, ci2.Created = now, now
	ci.Delivered.Last, ci2.Delivered.Last = nil, nil
	ci.AckFloor.Last, ci2.AckFloor.Last = nil, nil
	// Also clusters will be different.
	ci.Cluster, ci2.Cluster = nil, nil

	if !reflect.DeepEqual(ci, ci2) {
		t.Fatalf("Consumer infos did not match\n%+v\nvs\n%+v", ci, ci2)
	}
}

func TestJetStreamAllowDirectAfterUpdate(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"*"},
	})
	require_NoError(t, err)
	sendStreamMsg(t, nc, "foo", "msg")

	si, err := js.UpdateStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"*"},
		AllowDirect: true,
	})
	require_NoError(t, err)
	require_True(t, si.Config.AllowDirect)

	_, err = js.GetLastMsg("TEST", "foo", nats.DirectGet(), nats.MaxWait(100*time.Millisecond))
	require_NoError(t, err)

	// Make sure turning off works too.
	si, err = js.UpdateStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"*"},
		AllowDirect: false,
	})
	require_NoError(t, err)
	require_False(t, si.Config.AllowDirect)

	_, err = js.GetLastMsg("TEST", "foo", nats.DirectGet(), nats.MaxWait(100*time.Millisecond))
	require_Error(t, err)
}

func TestJetStreamSubjectBasedFilteredConsumers(t *testing.T) {
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		jetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q}
		accounts: {
			A: {
				jetstream: enabled
				users: [ {
					user: u,
					password: p
					permissions {
						publish {
							allow: [
								'ID.>',
								'$JS.API.INFO',
								'$JS.API.STREAM.>',
								'$JS.API.CONSUMER.INFO.>',
								'$JS.API.CONSUMER.CREATE.TEST.VIN-xxx.ID.foo.>', # Only allow ID.foo.
							]
							deny: [ '$JS.API.CONSUMER.CREATE.*', '$JS.API.CONSUMER.DURABLE.CREATE.*.*']
						}
					}
				} ]
			},
		}
	`, t.TempDir())))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s, nats.UserInfo("u", "p"), nats.ErrorHandler(noOpErrHandler))
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"ID.*.*"},
	})
	require_NoError(t, err)

	for i := 0; i < 100; i++ {
		js.Publish(fmt.Sprintf("ID.foo.%d", i*3), nil)
		js.Publish(fmt.Sprintf("ID.bar.%d", i*3+1), nil)
		js.Publish(fmt.Sprintf("ID.baz.%d", i*3+2), nil)
	}
	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_True(t, si.State.Msgs == 300)

	// Trying to create a consumer with non filtered API should fail.
	js, err = nc.JetStream(nats.MaxWait(200 * time.Millisecond))
	require_NoError(t, err)

	_, err = js.SubscribeSync("ID.foo.*")
	require_Error(t, err, nats.ErrTimeout, context.DeadlineExceeded)

	_, err = js.SubscribeSync("ID.foo.*", nats.Durable("dlc"))
	require_Error(t, err, nats.ErrTimeout, context.DeadlineExceeded)

	// Direct filtered should work.
	// Need to do by hand for now.
	ecSubj := fmt.Sprintf(JSApiConsumerCreateExT, "TEST", "VIN-xxx", "ID.foo.*")

	crReq := CreateConsumerRequest{
		Stream: "TEST",
		Config: ConsumerConfig{
			DeliverPolicy: DeliverLast,
			FilterSubject: "ID.foo.*",
			AckPolicy:     AckExplicit,
		},
	}
	req, err := json.Marshal(crReq)
	require_NoError(t, err)

	resp, err := nc.Request(ecSubj, req, 500*time.Millisecond)
	require_NoError(t, err)
	var ccResp JSApiConsumerCreateResponse
	err = json.Unmarshal(resp.Data, &ccResp)
	require_NoError(t, err)
	if ccResp.Error != nil {
		t.Fatalf("Unexpected error: %v", ccResp.Error)
	}
	cfg := ccResp.Config
	ci := ccResp.ConsumerInfo
	// Make sure we recognized as an ephemeral (since no durable was set) and that we have an InactiveThreshold.
	// Make sure we captured preferred ephemeral name.
	if ci.Name != "VIN-xxx" {
		t.Fatalf("Did not get correct name, expected %q got %q", "xxx", ci.Name)
	}
	if cfg.InactiveThreshold == 0 {
		t.Fatalf("Expected default inactive threshold to be set, got %v", cfg.InactiveThreshold)
	}

	// Make sure we can not use different consumer name since locked above.
	ecSubj = fmt.Sprintf(JSApiConsumerCreateExT, "TEST", "VIN-zzz", "ID.foo.*")
	_, err = nc.Request(ecSubj, req, 500*time.Millisecond)
	require_Error(t, err, nats.ErrTimeout)

	// Now check that we error when we mismatch filtersubject.
	crReq = CreateConsumerRequest{
		Stream: "TEST",
		Config: ConsumerConfig{
			DeliverPolicy: DeliverLast,
			FilterSubject: "ID.bar.*",
			AckPolicy:     AckExplicit,
		},
	}
	req, err = json.Marshal(crReq)
	require_NoError(t, err)

	ecSubj = fmt.Sprintf(JSApiConsumerCreateExT, "TEST", "VIN-xxx", "ID.foo.*")
	resp, err = nc.Request(ecSubj, req, 500*time.Millisecond)
	require_NoError(t, err)
	err = json.Unmarshal(resp.Data, &ccResp)
	require_NoError(t, err)
	checkNatsError(t, ccResp.Error, JSConsumerCreateFilterSubjectMismatchErr)

	// Now make sure if we change subject to match that we can not create a filtered consumer on ID.bar.>
	ecSubj = fmt.Sprintf(JSApiConsumerCreateExT, "TEST", "VIN-xxx", "ID.bar.*")
	_, err = nc.Request(ecSubj, req, 500*time.Millisecond)
	require_Error(t, err, nats.ErrTimeout)
}

func TestJetStreamStreamSubjectsOverlap(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo.*", "foo.A"},
	})
	require_Error(t, err)
	require_True(t, strings.Contains(err.Error(), "overlaps"))

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo.*"},
	})
	require_NoError(t, err)

	_, err = js.UpdateStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo.*", "foo.A"},
	})
	require_Error(t, err)
	require_True(t, strings.Contains(err.Error(), "overlaps"))

	_, err = js.UpdateStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo.bar.*", "foo.*.bar"},
	})
	require_Error(t, err)
	require_True(t, strings.Contains(err.Error(), "overlaps"))
}

func TestJetStreamStreamTransformOverlap(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo.>"},
	})
	require_NoError(t, err)

	_, err = js.AddStream(&nats.StreamConfig{
		Name: "MIRROR",
		Mirror: &nats.StreamSource{Name: "TEST",
			SubjectTransforms: []nats.SubjectTransformConfig{
				{
					Source:      "foo.*.bar",
					Destination: "baz",
				},
				{
					Source:      "foo.bar.*",
					Destination: "baz",
				},
			},
		}})
	require_Error(t, err)
	require_True(t, strings.Contains(err.Error(), "overlap"))

}

func TestJetStreamSuppressAllowDirect(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	si, err := js.AddStream(&nats.StreamConfig{
		Name:              "TEST",
		Subjects:          []string{"key.*"},
		MaxMsgsPerSubject: 1,
		AllowDirect:       true,
	})
	require_NoError(t, err)
	require_True(t, si.Config.AllowDirect)

	si, err = js.UpdateStream(&nats.StreamConfig{
		Name:              "TEST",
		Subjects:          []string{"key.*"},
		MaxMsgsPerSubject: 1,
		AllowDirect:       false,
	})
	require_NoError(t, err)
	require_False(t, si.Config.AllowDirect)

	sendStreamMsg(t, nc, "key.22", "msg")

	_, err = js.GetLastMsg("TEST", "foo", nats.DirectGet(), nats.MaxWait(100*time.Millisecond))
	require_Error(t, err)
}

func TestJetStreamAccountPurge(t *testing.T) {
	sysKp, syspub := createKey(t)
	sysJwt := encodeClaim(t, jwt.NewAccountClaims(syspub), syspub)
	sysCreds := newUser(t, sysKp)
	accKp, accpub := createKey(t)
	accClaim := jwt.NewAccountClaims(accpub)
	accClaim.Limits.JetStreamLimits.DiskStorage = 1024 * 1024 * 5
	accClaim.Limits.JetStreamLimits.MemoryStorage = 1024 * 1024 * 5
	accJwt := encodeClaim(t, accClaim, accpub)
	accCreds := newUser(t, accKp)

	storeDir := t.TempDir()

	cfg := createConfFile(t, []byte(fmt.Sprintf(`
        host: 127.0.0.1
        port:-1
        server_name: S1
        operator: %s
        system_account: %s
        resolver: {
                type: full
                dir: '%s/jwt'
        }
        jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s/js'}
`, ojwt, syspub, storeDir, storeDir)))
	defer os.Remove(cfg)

	s, o := RunServerWithConfig(cfg)
	updateJwt(t, s.ClientURL(), sysCreds, sysJwt, 1)
	updateJwt(t, s.ClientURL(), sysCreds, accJwt, 1)
	defer s.Shutdown()

	inspectDirs := func(t *testing.T, accTotal int) error {
		t.Helper()
		if accTotal == 0 {
			files, err := os.ReadDir(filepath.Join(o.StoreDir, "jetstream", accpub))
			require_True(t, len(files) == accTotal || err != nil)
		} else {
			files, err := os.ReadDir(filepath.Join(o.StoreDir, "jetstream", accpub, "streams"))
			require_NoError(t, err)
			require_True(t, len(files) == accTotal)
		}
		return nil
	}

	createTestData := func() {
		nc := natsConnect(t, s.ClientURL(), nats.UserCredentials(accCreds))
		defer nc.Close()
		js, err := nc.JetStream()
		require_NoError(t, err)
		_, err = js.AddStream(&nats.StreamConfig{
			Name:     "TEST1",
			Subjects: []string{"foo"},
		})
		require_NoError(t, err)
		_, err = js.AddConsumer("TEST1",
			&nats.ConsumerConfig{Durable: "DUR1",
				AckPolicy: nats.AckExplicitPolicy})
		require_NoError(t, err)
	}

	purge := func(t *testing.T) {
		t.Helper()
		var resp JSApiAccountPurgeResponse
		ncsys := natsConnect(t, s.ClientURL(), nats.UserCredentials(sysCreds))
		defer ncsys.Close()
		m, err := ncsys.Request(fmt.Sprintf(JSApiAccountPurgeT, accpub), nil, 5*time.Second)
		require_NoError(t, err)
		err = json.Unmarshal(m.Data, &resp)
		require_NoError(t, err)
		require_True(t, resp.Initiated)
	}

	createTestData()
	inspectDirs(t, 1)
	purge(t)
	inspectDirs(t, 0)
	createTestData()
	inspectDirs(t, 1)

	s.Shutdown()
	require_NoError(t, os.Remove(storeDir+"/jwt/"+accpub+".jwt"))

	s, o = RunServerWithConfig(o.ConfigFile)
	defer s.Shutdown()
	inspectDirs(t, 1)
	purge(t)
	inspectDirs(t, 0)
}

// For issue https://github.com/nats-io/nats-server/issues/3612
// Do auto cleanup.
func TestJetStreamDanglingMessageAutoCleanup(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "TEST",
		Subjects:  []string{"foo"},
		Retention: nats.InterestPolicy,
	})
	require_NoError(t, err)

	sub, err := js.PullSubscribe("foo", "dlc", nats.MaxAckPending(10))
	require_NoError(t, err)

	// Send 100 msgs
	n := 100
	for i := 0; i < n; i++ {
		sendStreamMsg(t, nc, "foo", "msg")
	}

	// Grab and ack 10 messages.
	for _, m := range fetchMsgs(t, sub, 10, time.Second) {
		m.AckSync()
	}

	ci, err := sub.ConsumerInfo()
	require_NoError(t, err)
	require_True(t, ci.AckFloor.Stream == 10)

	// Stop current
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()

	// We will hand move the ackfloor to simulate dangling message condition.
	cstore := filepath.Join(sd, "$G", "streams", "TEST", "obs", "dlc", "o.dat")

	buf, err := os.ReadFile(cstore)
	require_NoError(t, err)

	state, err := decodeConsumerState(buf)
	require_NoError(t, err)

	// Update from 10 for delivered and ack to 90.
	state.Delivered.Stream, state.Delivered.Consumer = 90, 90
	state.AckFloor.Stream, state.AckFloor.Consumer = 90, 90

	err = os.WriteFile(cstore, encodeConsumerState(state), defaultFilePerms)
	require_NoError(t, err)

	// Restart.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)

	if si.State.Msgs != 10 {
		t.Fatalf("Expected auto-cleanup to have worked but got %d msgs vs 10", si.State.Msgs)
	}
}

// Issue https://github.com/nats-io/nats-server/issues/3645
func TestJetStreamMsgIDHeaderCollision(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"ORDERS.*"},
	})
	require_NoError(t, err)

	m := nats.NewMsg("ORDERS.test")
	m.Header.Add(JSMsgId, "1")
	m.Data = []byte("ok")

	_, err = js.PublishMsg(m)
	require_NoError(t, err)

	m.Header = make(nats.Header)
	m.Header.Add("Orig-Nats-Msg-Id", "1")

	_, err = js.PublishMsg(m)
	require_NoError(t, err)

	m.Header = make(nats.Header)
	m.Header.Add("Original-Nats-Msg-Id", "1")

	_, err = js.PublishMsg(m)
	require_NoError(t, err)

	m.Header = make(nats.Header)
	m.Header.Add("Original-Nats-Msg-Id", "1")
	m.Header.Add("Really-Original-Nats-Msg-Id", "1")

	_, err = js.PublishMsg(m)
	require_NoError(t, err)

	m.Header = make(nats.Header)
	m.Header.Add("X", "Nats-Msg-Id:1")

	_, err = js.PublishMsg(m)
	require_NoError(t, err)

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)

	require_True(t, si.State.Msgs == 5)
}

// https://github.com/nats-io/nats-server/issues/3657
func TestJetStreamServerCrashOnPullConsumerDeleteWithInactiveThresholdAfterAck(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	sendStreamMsg(t, nc, "foo", "msg")

	sub, err := js.PullSubscribe("foo", "dlc", nats.InactiveThreshold(10*time.Second))
	require_NoError(t, err)

	msgs := fetchMsgs(t, sub, 1, time.Second)
	require_True(t, len(msgs) == 1)
	msgs[0].Ack()
	err = js.DeleteConsumer("TEST", "dlc")
	require_NoError(t, err)

	// If server crashes this will fail.
	_, err = js.StreamInfo("TEST")
	require_NoError(t, err)
}

// createConsumer is a temporary method until nats.go client supports multiple subjects.
// it is used where lowe level call on mset is not enough, as we want to test error validation.
func createConsumer(t *testing.T, nc *nats.Conn, stream string, config ConsumerConfig) JSApiConsumerCreateResponse {
	req, err := json.Marshal(&CreateConsumerRequest{Stream: stream, Config: config})
	require_NoError(t, err)

	resp, err := nc.Request(fmt.Sprintf("$JS.API.CONSUMER.DURABLE.CREATE.%s.%s", stream, config.Durable), req, time.Second*10)
	require_NoError(t, err)

	var apiResp JSApiConsumerCreateResponse
	require_NoError(t, json.Unmarshal(resp.Data, &apiResp))

	return apiResp
}

func TestJetStreamBothFiltersSet(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	if config := s.JetStreamConfig(); config != nil {
		defer removeDir(t, config.StoreDir)
	}
	defer s.Shutdown()

	nc, _ := jsClientConnect(t, s)
	defer nc.Close()
	acc := s.GlobalAccount()

	_, err := acc.addStream(&StreamConfig{
		Subjects: []string{"events.>"},
		Name:     "deliver",
	})
	require_NoError(t, err)

	resp := createConsumer(t, nc, "deliver", ConsumerConfig{
		FilterSubjects: []string{"events.one", "events.two"},
		FilterSubject:  "events.three",
		Durable:        "name",
	})
	require_True(t, resp.Error.ErrCode == 10136)
}

func TestJetStreamMultipleSubjectsPushBasic(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	if config := s.JetStreamConfig(); config != nil {
		defer removeDir(t, config.StoreDir)
	}
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	mset, err := s.GlobalAccount().addStream(&StreamConfig{
		Subjects: []string{"events", "data", "other"},
		Name:     "deliver",
	})
	require_NoError(t, err)

	_, err = mset.addConsumer(&ConsumerConfig{
		FilterSubjects: []string{"events", "data"},
		Durable:        "name",
		DeliverSubject: "push",
	})
	require_NoError(t, err)

	sub, err := nc.SubscribeSync("push")
	require_NoError(t, err)

	sendStreamMsg(t, nc, "other", "10")
	sendStreamMsg(t, nc, "events", "0")
	sendStreamMsg(t, nc, "data", "1")
	sendStreamMsg(t, nc, "events", "2")
	sendStreamMsg(t, nc, "events", "3")
	sendStreamMsg(t, nc, "other", "10")
	sendStreamMsg(t, nc, "data", "4")
	sendStreamMsg(t, nc, "data", "5")

	for i := 0; i < 6; i++ {
		msg, err := sub.NextMsg(time.Second * 1)
		require_NoError(t, err)
		if fmt.Sprintf("%v", i) != string(msg.Data) {
			t.Fatalf("bad sequence. Expected %v, got %v", i, string(msg.Data))
		}
	}
	info, err := js.ConsumerInfo("deliver", "name")
	require_NoError(t, err)
	require_True(t, info.AckFloor.Consumer == 6)
	require_True(t, info.AckFloor.Stream == 8)
}
func TestJetStreamMultipleSubjectsBasic(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	if config := s.JetStreamConfig(); config != nil {
		defer removeDir(t, config.StoreDir)
	}
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()
	acc := s.GlobalAccount()

	mset, err := acc.addStream(&StreamConfig{
		Subjects: []string{"events", "data", "other"},
		Name:     "deliver",
	})
	require_NoError(t, err)

	mset.addConsumer(&ConsumerConfig{
		FilterSubjects: []string{"events", "data"},
		Durable:        "name",
	})
	require_NoError(t, err)

	sendStreamMsg(t, nc, "other", "10")
	sendStreamMsg(t, nc, "events", "0")
	sendStreamMsg(t, nc, "data", "1")
	sendStreamMsg(t, nc, "events", "2")
	sendStreamMsg(t, nc, "events", "3")
	sendStreamMsg(t, nc, "other", "10")
	sendStreamMsg(t, nc, "data", "4")
	sendStreamMsg(t, nc, "data", "5")

	consumer, err := js.PullSubscribe("", "name", nats.Bind("deliver", "name"))
	require_NoError(t, err)

	msg, err := consumer.Fetch(6)
	require_NoError(t, err)

	for i, msg := range msg {
		if fmt.Sprintf("%v", i) != string(msg.Data) {
			t.Fatalf("bad sequence. Expected %v, got %v", i, string(msg.Data))
		}
	}
	_, err = js.ConsumerInfo("deliver", "name")
	require_NoError(t, err)
}

func TestJetStreamKVDelete(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	if config := s.JetStreamConfig(); config != nil {
		defer removeDir(t, config.StoreDir)
	}
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	kv, err := js.CreateKeyValue(&nats.KeyValueConfig{
		Bucket:  "deletion",
		History: 10,
	})
	require_NoError(t, err)
	kv.Put("a", nil)
	kv.Put("a.a", nil)
	kv.Put("a.b", nil)
	kv.Put("a.b.c", nil)

	keys, err := kv.Keys()
	require_NoError(t, err)
	require_True(t, len(keys) == 4)

	info, err := js.AddConsumer("KV_deletion", &nats.ConsumerConfig{
		Name:           "keys",
		FilterSubject:  "$KV.deletion.a.*",
		DeliverPolicy:  nats.DeliverLastPerSubjectPolicy,
		DeliverSubject: "keys",
		MaxDeliver:     1,
		AckPolicy:      nats.AckNonePolicy,
		MemoryStorage:  true,
		FlowControl:    true,
		Heartbeat:      time.Second * 5,
	})
	require_NoError(t, err)
	require_True(t, info.NumPending == 2)

	sub, err := js.SubscribeSync("$KV.deletion.a.*", nats.Bind("KV_deletion", "keys"))
	require_NoError(t, err)

	_, err = sub.NextMsg(time.Second * 1)
	require_NoError(t, err)
	_, err = sub.NextMsg(time.Second * 1)
	require_NoError(t, err)
	msg, err := sub.NextMsg(time.Second * 1)
	require_True(t, msg == nil)
	require_Error(t, err)

	require_NoError(t, kv.Delete("a.a"))
	require_NoError(t, kv.Delete("a.b"))

	watcher, err := kv.WatchAll()
	require_NoError(t, err)

	updates := watcher.Updates()

	keys = []string{}
	for v := range updates {
		if v == nil {
			break
		}
		if v.Operation() == nats.KeyValueDelete {
			keys = append(keys, v.Key())
		}
	}
	require_True(t, len(keys) == 2)
}

func TestJetStreamDeliverLastPerSubjectWithKV(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	if config := s.JetStreamConfig(); config != nil {
		defer removeDir(t, config.StoreDir)
	}
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:              "TEST",
		MaxMsgsPerSubject: 5,
		Subjects:          []string{"kv.>"},
	})
	require_NoError(t, err)

	sendStreamMsg(t, nc, "kv.a", "bad")
	sendStreamMsg(t, nc, "kv.a", "bad")
	sendStreamMsg(t, nc, "kv.a", "bad")
	sendStreamMsg(t, nc, "kv.a", "a")
	sendStreamMsg(t, nc, "kv.a.b", "bad")
	sendStreamMsg(t, nc, "kv.a.b", "bad")
	sendStreamMsg(t, nc, "kv.a.b", "a.b")
	sendStreamMsg(t, nc, "kv.a.b.c", "bad")
	sendStreamMsg(t, nc, "kv.a.b.c", "bad")
	sendStreamMsg(t, nc, "kv.a.b.c", "bad")
	sendStreamMsg(t, nc, "kv.a.b.c", "a.b.c")

	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{
		Name:           "CONSUMER",
		FilterSubject:  "kv.>",
		DeliverPolicy:  nats.DeliverLastPerSubjectPolicy,
		DeliverSubject: "deliver",
		MaxDeliver:     1,
		AckPolicy:      nats.AckNonePolicy,
		MemoryStorage:  true,
		FlowControl:    true,
		Heartbeat:      time.Second * 5,
	})
	require_NoError(t, err)

	sub, err := js.SubscribeSync("kv.>", nats.Bind("TEST", "CONSUMER"))
	require_NoError(t, err)

	for i := 1; i <= 3; i++ {
		_, err := sub.NextMsg(time.Second * 1)
		require_NoError(t, err)
	}

	msg, err := sub.NextMsg(time.Second * 1)
	if err == nil || msg != nil {
		t.Fatalf("should not get any more messages")
	}
}

func TestJetStreamStreamUpdateSubjectsOverlapOthers(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"TEST"},
	})
	require_NoError(t, err)

	_, err = js.UpdateStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"TEST", "foo.a"},
	})
	require_NoError(t, err)

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST2",
		Subjects: []string{"TEST2"},
	})
	require_NoError(t, err)

	// we expect an error updating stream TEST2 with subject that overlaps that used by TEST
	// foo.a fails too, but foo.* also double-check for sophisticated overlap match
	_, err = js.UpdateStream(&nats.StreamConfig{
		Name:     "TEST2",
		Subjects: []string{"TEST2", "foo.*"},
	})
	require_Error(t, err)
	require_Contains(t, err.Error(), "overlap")
}

func TestJetStreamMetaDataFailOnKernelFault(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	for i := 0; i < 10; i++ {
		sendStreamMsg(t, nc, "foo", "OK")
	}

	sd := s.JetStreamConfig().StoreDir
	sdir := filepath.Join(sd, "$G", "streams", "TEST")
	s.Shutdown()

	// Emulate if the kernel did not flush out to disk the meta information.
	// so we will zero out both meta.inf and meta.sum.
	err = os.WriteFile(filepath.Join(sdir, JetStreamMetaFile), nil, defaultFilePerms)
	require_NoError(t, err)

	err = os.WriteFile(filepath.Join(sdir, JetStreamMetaFileSum), nil, defaultFilePerms)
	require_NoError(t, err)

	// Restart.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	// The stream will have not been recovered. So err is normal.
	_, err = js.StreamInfo("TEST")
	require_Error(t, err)

	// Make sure we are signaled here from healthz
	hs := s.healthz(nil)
	const expected = "JetStream stream '$G > TEST' could not be recovered"
	if hs.Status != "unavailable" || hs.Error == _EMPTY_ {
		t.Fatalf("Expected healthz to return an error")
	} else if hs.Error != expected {
		t.Fatalf("Expected healthz error %q got %q", expected, hs.Error)
	}

	// If we add it back, this should recover the msgs.
	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	// Make sure we recovered.
	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_True(t, si.State.Msgs == 10)

	// Now if we restart the server, meta should be correct,
	// and the stream should be restored.
	s.Shutdown()

	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	// Make sure we recovered the stream correctly after re-adding.
	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_True(t, si.State.Msgs == 10)
}

// https://github.com/nats-io/nats-server/issues/3734
func TestJetStreamMsgBlkFailOnKernelFault(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
		MaxBytes: 10 * 1024 * 1024, // 10MB
	})
	require_NoError(t, err)

	msgSize := 1024 * 1024 // 1MB
	msg := make([]byte, msgSize)
	crand.Read(msg)

	for i := 0; i < 20; i++ {
		_, err := js.Publish("foo", msg)
		require_NoError(t, err)
	}

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_True(t, si.State.Bytes < uint64(si.Config.MaxBytes))

	// Now emulate a kernel fault that fails to write the last blk properly.
	mset, err := s.GlobalAccount().lookupStream("TEST")
	require_NoError(t, err)

	mset.mu.RLock()
	fs := mset.store.(*fileStore)
	fs.mu.RLock()
	require_True(t, len(fs.blks) > 2)
	// Here we do not grab the last one, which we handle correctly. We grab an interior one near the end.
	lmbf := fs.blks[len(fs.blks)-2].mfn
	fs.mu.RUnlock()
	mset.mu.RUnlock()

	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()

	// Remove block.
	require_NoError(t, os.Remove(lmbf))

	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	_, err = js.GetMsg("TEST", 17)
	require_Error(t, err, nats.ErrMsgNotFound)

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_True(t, si.State.NumDeleted == 3)

	// Test detailed version as well.
	si, err = js.StreamInfo("TEST", &nats.StreamInfoRequest{DeletedDetails: true})
	require_NoError(t, err)
	require_True(t, si.State.NumDeleted == 3)
	if !reflect.DeepEqual(si.State.Deleted, []uint64{16, 17, 18}) {
		t.Fatalf("Expected deleted of %+v, got %+v", []uint64{16, 17, 18}, si.State.Deleted)
	}

	for i := 0; i < 20; i++ {
		_, err := js.Publish("foo", msg)
		require_NoError(t, err)
	}

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	if si.State.Bytes > uint64(si.Config.MaxBytes) {
		t.Fatalf("MaxBytes not enforced with empty interior msg blk, max %v, bytes %v",
			friendlyBytes(si.Config.MaxBytes), friendlyBytes(int64(si.State.Bytes)))
	}
}

func TestJetStreamPurgeExAndAccounting(t *testing.T) {
	cases := []struct {
		name string
		cfg  *nats.StreamConfig
	}{
		{name: "MemoryStore",
			cfg: &nats.StreamConfig{
				Name:     "TEST",
				Storage:  nats.MemoryStorage,
				Subjects: []string{"*"},
			}},
		{name: "FileStore",
			cfg: &nats.StreamConfig{
				Name:     "TEST",
				Storage:  nats.FileStorage,
				Subjects: []string{"*"},
			}},
	}
	for _, c := range cases {
		s := RunBasicJetStreamServer(t)
		defer s.Shutdown()

		// Client for API requests.
		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		_, err := js.AddStream(c.cfg)
		require_NoError(t, err)

		msg := []byte("accounting")
		for i := 0; i < 100; i++ {
			_, err = js.Publish("foo", msg)
			require_NoError(t, err)
			_, err = js.Publish("bar", msg)
			require_NoError(t, err)
		}

		info, err := js.AccountInfo()
		require_NoError(t, err)

		err = js.PurgeStream("TEST", &nats.StreamPurgeRequest{Subject: "foo"})
		require_NoError(t, err)

		ninfo, err := js.AccountInfo()
		require_NoError(t, err)

		// Make sure we did the proper accounting.
		if c.cfg.Storage == nats.MemoryStorage {
			if ninfo.Memory != info.Memory/2 {
				t.Fatalf("Accounting information incorrect for Memory: %d vs %d",
					ninfo.Memory, info.Memory/2)
			}
		} else {
			if ninfo.Store != info.Store/2 {
				t.Fatalf("Accounting information incorrect for FileStore: %d vs %d",
					ninfo.Store, info.Store/2)
			}
		}
	}
}

func TestJetStreamRollup(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	const STREAM = "S"
	const SUBJ = "S.*"

	js.AddStream(&nats.StreamConfig{
		Name:        STREAM,
		Subjects:    []string{SUBJ},
		AllowRollup: true,
	})

	for i := 1; i <= 10; i++ {
		sendStreamMsg(t, nc, "S.A", fmt.Sprintf("%v", i))
		sendStreamMsg(t, nc, "S.B", fmt.Sprintf("%v", i))
	}

	sinfo, err := js.StreamInfo(STREAM)
	require_NoError(t, err)
	require_True(t, sinfo.State.Msgs == 20)

	cinfo, err := js.AddConsumer(STREAM, &nats.ConsumerConfig{
		Durable:       "DUR-A",
		FilterSubject: "S.A",
		AckPolicy:     nats.AckExplicitPolicy,
	})
	require_NoError(t, err)
	require_True(t, cinfo.NumPending == 10)

	m := nats.NewMsg("S.A")
	m.Header.Set(JSMsgRollup, JSMsgRollupSubject)

	_, err = js.PublishMsg(m)
	require_NoError(t, err)

	cinfo, err = js.ConsumerInfo("S", "DUR-A")
	require_NoError(t, err)
	require_True(t, cinfo.NumPending == 1)

	sinfo, err = js.StreamInfo(STREAM)
	require_NoError(t, err)
	require_True(t, sinfo.State.Msgs == 11)

	cinfo, err = js.AddConsumer(STREAM, &nats.ConsumerConfig{
		Durable:       "DUR-B",
		FilterSubject: "S.B",
		AckPolicy:     nats.AckExplicitPolicy,
	})
	require_NoError(t, err)
	require_True(t, cinfo.NumPending == 10)
}

func TestJetStreamPartialPurgeWithAckPending(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	nmsgs := 100
	for i := 0; i < nmsgs; i++ {
		sendStreamMsg(t, nc, "foo", "OK")
	}
	sub, err := js.PullSubscribe("foo", "dlc", nats.AckWait(time.Second))
	require_NoError(t, err)

	// Queue up all for ack pending.
	_, err = sub.Fetch(nmsgs)
	require_NoError(t, err)

	keep := nmsgs / 2
	require_NoError(t, js.PurgeStream("TEST", &nats.StreamPurgeRequest{Keep: uint64(keep)}))

	// Should be able to be redelivered now.
	time.Sleep(2 * time.Second)

	ci, err := js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)
	// Make sure we calculated correctly.
	require_True(t, ci.AckFloor.Consumer == uint64(keep))
	require_True(t, ci.AckFloor.Stream == uint64(keep))
	require_True(t, ci.NumAckPending == keep)
	require_True(t, ci.NumPending == 0)

	for i := 0; i < nmsgs; i++ {
		sendStreamMsg(t, nc, "foo", "OK")
	}

	ci, err = js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)
	// Make sure we calculated correctly.
	// Top 3 will be same.
	require_True(t, ci.AckFloor.Consumer == uint64(keep))
	require_True(t, ci.AckFloor.Stream == uint64(keep))
	require_True(t, ci.NumAckPending == keep)
	require_True(t, ci.NumPending == uint64(nmsgs))
	require_True(t, ci.NumRedelivered == 0)

	msgs, err := sub.Fetch(keep)
	require_NoError(t, err)
	require_True(t, len(msgs) == keep)

	ci, err = js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)
	// Make sure we calculated correctly.
	require_True(t, ci.Delivered.Consumer == uint64(nmsgs+keep))
	require_True(t, ci.Delivered.Stream == uint64(nmsgs))
	require_True(t, ci.AckFloor.Consumer == uint64(keep))
	require_True(t, ci.AckFloor.Stream == uint64(keep))
	require_True(t, ci.NumAckPending == keep)
	require_True(t, ci.NumPending == uint64(nmsgs))
	require_True(t, ci.NumRedelivered == keep)

	// Ack all.
	for _, m := range msgs {
		m.Ack()
	}
	nc.Flush()

	ci, err = js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)
	// Same for Delivered
	require_True(t, ci.Delivered.Consumer == uint64(nmsgs+keep))
	require_True(t, ci.Delivered.Stream == uint64(nmsgs))
	require_True(t, ci.AckFloor.Consumer == uint64(nmsgs+keep))
	require_True(t, ci.AckFloor.Stream == uint64(nmsgs))
	require_True(t, ci.NumAckPending == 0)
	require_True(t, ci.NumPending == uint64(nmsgs))
	require_True(t, ci.NumRedelivered == 0)

	msgs, err = sub.Fetch(nmsgs)
	require_NoError(t, err)
	require_True(t, len(msgs) == nmsgs)

	// Ack all again
	for _, m := range msgs {
		m.Ack()
	}
	nc.Flush()

	ci, err = js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)
	// Make sure we calculated correctly.
	require_True(t, ci.Delivered.Consumer == uint64(nmsgs*2+keep))
	require_True(t, ci.Delivered.Stream == uint64(nmsgs*2))
	require_True(t, ci.AckFloor.Consumer == uint64(nmsgs*2+keep))
	require_True(t, ci.AckFloor.Stream == uint64(nmsgs*2))
	require_True(t, ci.NumAckPending == 0)
	require_True(t, ci.NumPending == 0)
	require_True(t, ci.NumRedelivered == 0)
}

func TestJetStreamPurgeWithRedeliveredPending(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
	})
	require_NoError(t, err)

	nmsgs := 100
	for i := 0; i < nmsgs; i++ {
		sendStreamMsg(t, nc, "foo", "OK")
	}
	sub, err := js.PullSubscribe("foo", "dlc", nats.AckWait(time.Second))
	require_NoError(t, err)

	// Queue up all for ack pending.
	msgs, err := sub.Fetch(nmsgs)
	require_NoError(t, err)
	require_True(t, len(msgs) == nmsgs)

	// Should be able to be redelivered now.
	time.Sleep(2 * time.Second)

	// Queue up all for ack pending again.
	msgs, err = sub.Fetch(nmsgs)
	require_NoError(t, err)
	require_True(t, len(msgs) == nmsgs)

	require_NoError(t, js.PurgeStream("TEST"))

	ci, err := js.ConsumerInfo("TEST", "dlc")
	require_NoError(t, err)

	require_True(t, ci.Delivered.Consumer == uint64(2*nmsgs))
	require_True(t, ci.Delivered.Stream == uint64(nmsgs))
	require_True(t, ci.AckFloor.Consumer == uint64(2*nmsgs))
	require_True(t, ci.AckFloor.Stream == uint64(nmsgs))
	require_True(t, ci.NumAckPending == 0)
	require_True(t, ci.NumPending == 0)
	require_True(t, ci.NumRedelivered == 0)
}

func TestJetStreamStreamUpdateWithExternalSource(t *testing.T) {
	ho := DefaultTestOptions
	ho.Port = -1
	ho.LeafNode.Host = "127.0.0.1"
	ho.LeafNode.Port = -1
	ho.JetStream = true
	ho.JetStreamDomain = "hub"
	ho.StoreDir = t.TempDir()
	hs := RunServer(&ho)
	defer hs.Shutdown()

	lu, err := url.Parse(fmt.Sprintf("nats://127.0.0.1:%d", ho.LeafNode.Port))
	require_NoError(t, err)

	lo1 := DefaultTestOptions
	lo1.Port = -1
	lo1.ServerName = "a-leaf"
	lo1.JetStream = true
	lo1.StoreDir = t.TempDir()
	lo1.JetStreamDomain = "a-leaf"
	lo1.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{lu}}}
	l1 := RunServer(&lo1)
	defer l1.Shutdown()

	checkLeafNodeConnected(t, l1)

	// Test sources with `External` provided
	ncl, jsl := jsClientConnect(t, l1)
	defer ncl.Close()

	// Hub stream.
	_, err = jsl.AddStream(&nats.StreamConfig{Name: "stream", Subjects: []string{"leaf"}})
	require_NoError(t, err)

	nch, jsh := jsClientConnect(t, hs)
	defer nch.Close()

	// Leaf stream.
	// Both streams uses the same name, as we're testing if overlap does not check against itself
	// if `External` stream has the same name.
	_, err = jsh.AddStream(&nats.StreamConfig{
		Name:     "stream",
		Subjects: []string{"hub"},
	})
	require_NoError(t, err)

	// Add `Sources`.
	// This should not validate subjects overlap against itself.
	_, err = jsh.UpdateStream(&nats.StreamConfig{
		Name:     "stream",
		Subjects: []string{"hub"},
		Sources: []*nats.StreamSource{
			{
				Name:          "stream",
				FilterSubject: "leaf",
				External: &nats.ExternalStream{
					APIPrefix: "$JS.a-leaf.API",
				},
			},
		},
	})
	require_NoError(t, err)

	// Specifying not existing FilterSubject should also be fine, as we do not validate `External` stream.
	_, err = jsh.UpdateStream(&nats.StreamConfig{
		Name:     "stream",
		Subjects: []string{"hub"},
		Sources: []*nats.StreamSource{
			{
				Name:          "stream",
				FilterSubject: "foo",
				External: &nats.ExternalStream{
					APIPrefix: "$JS.a-leaf.API",
				},
			},
		},
	})
	require_NoError(t, err)
}

func TestJetStreamKVHistoryRegression(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	for _, storage := range []nats.StorageType{nats.FileStorage, nats.MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			js.DeleteKeyValue("TEST")

			kv, err := js.CreateKeyValue(&nats.KeyValueConfig{
				Bucket:  "TEST",
				History: 4,
				Storage: storage,
			})
			require_NoError(t, err)

			r1, err := kv.Create("foo", []byte("a"))
			require_NoError(t, err)

			_, err = kv.Update("foo", []byte("ab"), r1)
			require_NoError(t, err)

			err = kv.Delete("foo")
			require_NoError(t, err)

			_, err = kv.Create("foo", []byte("abc"))
			require_NoError(t, err)

			err = kv.Delete("foo")
			require_NoError(t, err)

			history, err := kv.History("foo")
			require_NoError(t, err)
			require_True(t, len(history) == 4)

			_, err = kv.Update("foo", []byte("abcd"), history[len(history)-1].Revision())
			require_NoError(t, err)

			err = kv.Purge("foo")
			require_NoError(t, err)

			_, err = kv.Create("foo", []byte("abcde"))
			require_NoError(t, err)

			err = kv.Purge("foo")
			require_NoError(t, err)

			history, err = kv.History("foo")
			require_NoError(t, err)
			require_True(t, len(history) == 1)
		})
	}
}

func TestJetStreamSnapshotRestoreStallAndHealthz(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "ORDERS",
		Subjects: []string{"orders.*"},
	})
	require_NoError(t, err)

	for i := 0; i < 1000; i++ {
		sendStreamMsg(t, nc, "orders.created", "new order")
	}

	hs := s.healthz(nil)
	if hs.Status != "ok" || hs.Error != _EMPTY_ {
		t.Fatalf("Expected health to be ok, got %+v", hs)
	}

	// Simulate the staging directory for restores. This is normally cleaned up
	// but since its at the root of the storage directory make sure healthz is not affected.
	snapDir := filepath.Join(s.getJetStream().config.StoreDir, snapStagingDir)
	require_NoError(t, os.MkdirAll(snapDir, defaultDirPerms))

	// Make sure healthz ok.
	hs = s.healthz(nil)
	if hs.Status != "ok" || hs.Error != _EMPTY_ {
		t.Fatalf("Expected health to be ok, got %+v", hs)
	}
}

// https://github.com/nats-io/nats-server/pull/4163
func TestJetStreamMaxBytesIgnored(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"*"},
		MaxBytes: 10 * 1024 * 1024,
	})
	require_NoError(t, err)

	msg := bytes.Repeat([]byte("A"), 1024*1024)

	for i := 0; i < 10; i++ {
		_, err := js.Publish("x", msg)
		require_NoError(t, err)
	}

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_True(t, si.State.Msgs == 9)

	// Stop current
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()

	// We will truncate blk file.
	mdir := filepath.Join(sd, "$G", "streams", "TEST", "msgs")
	// Truncate blk
	err = os.WriteFile(filepath.Join(mdir, "1.blk"), nil, defaultFilePerms)
	require_NoError(t, err)

	// Restart.
	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	for i := 0; i < 10; i++ {
		_, err := js.Publish("x", msg)
		require_NoError(t, err)
	}

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_True(t, si.State.Bytes <= 10*1024*1024)
}

func TestJetStreamLastSequenceBySubjectConcurrent(t *testing.T) {
	for _, st := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(st.String(), func(t *testing.T) {
			c := createJetStreamClusterExplicit(t, "JSC", 3)
			defer c.shutdown()

			nc0, js0 := jsClientConnect(t, c.randomServer())
			defer nc0.Close()

			nc1, js1 := jsClientConnect(t, c.randomServer())
			defer nc1.Close()

			cfg := StreamConfig{
				Name:     "KV",
				Subjects: []string{"kv.>"},
				Storage:  st,
				Replicas: 3,
			}

			req, err := json.Marshal(cfg)
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}
			// Do manually for now.
			m, err := nc0.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second)
			require_NoError(t, err)
			si, err := js0.StreamInfo("KV")
			if err != nil {
				t.Fatalf("Unexpected error: %v, respmsg: %q", err, string(m.Data))
			}
			if si == nil || si.Config.Name != "KV" {
				t.Fatalf("StreamInfo is not correct %+v", si)
			}

			pub := func(js nats.JetStreamContext, subj, data, seq string) {
				t.Helper()
				m := nats.NewMsg(subj)
				m.Data = []byte(data)
				m.Header.Set(JSExpectedLastSubjSeq, seq)
				js.PublishMsg(m)
			}

			ready := make(chan struct{})
			wg := &sync.WaitGroup{}
			wg.Add(2)

			go func() {
				<-ready
				pub(js0, "kv.foo", "0-0", "0")
				pub(js0, "kv.foo", "0-1", "1")
				pub(js0, "kv.foo", "0-2", "2")
				wg.Done()
			}()

			go func() {
				<-ready
				pub(js1, "kv.foo", "1-0", "0")
				pub(js1, "kv.foo", "1-1", "1")
				pub(js1, "kv.foo", "1-2", "2")
				wg.Done()
			}()

			time.Sleep(50 * time.Millisecond)
			close(ready)
			wg.Wait()

			// Read the messages.
			sub, err := js0.PullSubscribe(_EMPTY_, _EMPTY_, nats.BindStream("KV"))
			require_NoError(t, err)
			msgs, err := sub.Fetch(10)
			require_NoError(t, err)
			if len(msgs) != 3 {
				t.Errorf("Expected 3 messages, got %d", len(msgs))
			}
			for i, m := range msgs {
				if m.Header.Get(JSExpectedLastSubjSeq) != fmt.Sprint(i) {
					t.Errorf("Expected %d for last sequence, got %q", i, m.Header.Get(JSExpectedLastSubjSeq))
				}
			}
		})
	}
}

func TestJetStreamServerReencryption(t *testing.T) {
	storeDir := t.TempDir()

	var i int
	for _, algo := range []struct {
		from string
		to   string
	}{
		{"aes", "aes"},
		{"aes", "chacha"},
		{"chacha", "chacha"},
		{"chacha", "aes"},
	} {
		for _, compression := range []StoreCompression{NoCompression, S2Compression} {
			t.Run(fmt.Sprintf("%s_to_%s/%s", algo.from, algo.to, compression), func(t *testing.T) {
				i++
				streamName := fmt.Sprintf("TEST_%d", i)
				subjectName := fmt.Sprintf("foo_%d", i)
				expected := 30

				checkStream := func(js nats.JetStreamContext) {
					si, err := js.StreamInfo(streamName)
					if err != nil {
						t.Fatal(err)
					}

					if si.State.Msgs != uint64(expected) {
						t.Fatalf("Should be %d messages but got %d messages", expected, si.State.Msgs)
					}

					sub, err := js.PullSubscribe(subjectName, "")
					if err != nil {
						t.Fatalf("Unexpected error: %v", err)
					}

					c := 0
					for _, m := range fetchMsgs(t, sub, expected, 5*time.Second) {
						m.AckSync()
						c++
					}
					if c != expected {
						t.Fatalf("Should have read back %d messages but got %d messages", expected, c)
					}
				}

				// First off, we start up using the original encryption key and algorithm.
				// We'll create a stream and populate it with some messages.
				t.Run("setup", func(t *testing.T) {
					conf := createConfFile(t, []byte(fmt.Sprintf(`
					server_name: S22
					listen: 127.0.0.1:-1
					jetstream: {
						key: %q,
						cipher: %s,
						store_dir: %q
					}
				`, "firstencryptionkey", algo.from, storeDir)))

					s, _ := RunServerWithConfig(conf)
					defer s.Shutdown()

					nc, js := jsClientConnect(t, s)
					defer nc.Close()

					cfg := &StreamConfig{
						Name:        streamName,
						Subjects:    []string{subjectName},
						Storage:     FileStorage,
						Compression: compression,
					}
					if _, err := jsStreamCreate(t, nc, cfg); err != nil {
						t.Fatalf("Unexpected error: %v", err)
					}

					payload := strings.Repeat("A", 512*1024)
					for i := 0; i < expected; i++ {
						if _, err := js.Publish(subjectName, []byte(payload)); err != nil {
							t.Fatalf("Unexpected publish error: %v", err)
						}
					}

					checkStream(js)
				})

				// Next up, we will restart the server, this time with both the new key
				// and algorithm and also the old key. At startup, the server will detect
				// the change in encryption key and/or algorithm and re-encrypt the stream.
				t.Run("reencrypt", func(t *testing.T) {
					conf := createConfFile(t, []byte(fmt.Sprintf(`
					server_name: S22
					listen: 127.0.0.1:-1
					jetstream: {
						key: %q,
						cipher: %s,
						prev_key: %q,
						store_dir: %q
					}
				`, "secondencryptionkey", algo.to, "firstencryptionkey", storeDir)))

					s, _ := RunServerWithConfig(conf)
					defer s.Shutdown()

					nc, js := jsClientConnect(t, s)
					defer nc.Close()

					checkStream(js)
				})

				// Finally, we'll restart the server using only the new key and algorithm.
				// At this point everything should have been re-encrypted, so we should still
				// be able to access the stream.
				t.Run("restart", func(t *testing.T) {
					conf := createConfFile(t, []byte(fmt.Sprintf(`
					server_name: S22
					listen: 127.0.0.1:-1
					jetstream: {
						key: %q,
						cipher: %s,
						store_dir: %q
					}
				`, "secondencryptionkey", algo.to, storeDir)))

					s, _ := RunServerWithConfig(conf)
					defer s.Shutdown()

					nc, js := jsClientConnect(t, s)
					defer nc.Close()

					checkStream(js)
				})
			})
		}
	}
}

func TestJetStreamLimitsToInterestPolicy(t *testing.T) {
	c := createJetStreamClusterExplicit(t, "JSC", 3)
	defer c.shutdown()

	nc, js := jsClientConnect(t, c.leader())
	defer nc.Close()

	// This is the index of the consumer that we'll create as R1
	// instead of R3, just to prove that it blocks the stream
	// update from happening properly.
	singleReplica := 3

	streamCfg := nats.StreamConfig{
		Name:      "TEST",
		Subjects:  []string{"foo"},
		Retention: nats.LimitsPolicy,
		Storage:   nats.MemoryStorage,
		Replicas:  3,
	}

	stream, err := js.AddStream(&streamCfg)
	require_NoError(t, err)

	for i := 0; i < 10; i++ {
		replicas := streamCfg.Replicas
		if i == singleReplica {
			// Make one of the consumers R1 so that we can check
			// that the switch to interest-based retention is also
			// turning it into an R3 consumer.
			replicas = 1
		}
		cname := fmt.Sprintf("test_%d", i)
		_, err := js.AddConsumer("TEST", &nats.ConsumerConfig{
			Name:      cname,
			Durable:   cname,
			AckPolicy: nats.AckAllPolicy,
			Replicas:  replicas,
		})
		require_NoError(t, err)
	}

	for i := 0; i < 20; i++ {
		_, err := js.Publish("foo", []byte{1, 2, 3, 4, 5})
		require_NoError(t, err)
	}

	// Pull 10 or more messages from the stream. We will never pull
	// less than 10, which guarantees that the lowest ack floor of
	// all consumers should be 10.
	for i := 0; i < 10; i++ {
		cname := fmt.Sprintf("test_%d", i)
		count := 10 + i // At least 10 messages

		sub, err := js.PullSubscribe("foo", cname)
		require_NoError(t, err)

		msgs, err := sub.Fetch(count)
		require_NoError(t, err)
		require_Equal(t, len(msgs), count)
		require_NoError(t, msgs[len(msgs)-1].AckSync())

		// At this point the ack floor should match the count of
		// messages we received.
		info, err := js.ConsumerInfo("TEST", cname)
		require_NoError(t, err)
		require_Equal(t, info.AckFloor.Consumer, uint64(count))
	}

	// Try updating to interest-based. This should fail because
	// we have a consumer that is R1 on an R3 stream.
	streamCfg = stream.Config
	streamCfg.Retention = nats.InterestPolicy
	_, err = js.UpdateStream(&streamCfg)
	require_Error(t, err)

	// Now we'll make the R1 consumer an R3.
	cname := fmt.Sprintf("test_%d", singleReplica)
	cinfo, err := js.ConsumerInfo("TEST", cname)
	require_NoError(t, err)

	cinfo.Config.Replicas = streamCfg.Replicas
	_, _ = js.UpdateConsumer("TEST", &cinfo.Config)
	// TODO(nat): The jsConsumerCreateRequest update doesn't always
	// respond when there are no errors updating a consumer, so this
	// nearly always returns a timeout, despite actually doing what
	// it should. We'll make sure the replicas were updated by doing
	// another consumer info just to be sure.
	// require_NoError(t, err)
	c.waitOnAllCurrent()
	c.waitOnConsumerLeader(globalAccountName, "TEST", cname)
	cinfo, err = js.ConsumerInfo("TEST", cname)
	require_NoError(t, err)
	require_Equal(t, cinfo.Config.Replicas, streamCfg.Replicas)
	require_Equal(t, len(cinfo.Cluster.Replicas), streamCfg.Replicas-1)

	// This time it should succeed.
	_, err = js.UpdateStream(&streamCfg)
	require_NoError(t, err)

	// We need to wait for all nodes to have applied the new stream
	// configuration.
	c.waitOnAllCurrent()

	// Now we should only have 10 messages left in the stream, as
	// each consumer has acked at least the first 10 messages.
	info, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, info.State.FirstSeq, 11)
	require_Equal(t, info.State.Msgs, 10)
}

func TestJetStreamLimitsToInterestPolicyWhileAcking(t *testing.T) {
	for _, st := range []nats.StorageType{nats.FileStorage, nats.MemoryStorage} {
		t.Run(st.String(), func(t *testing.T) {
			c := createJetStreamClusterExplicit(t, "JSC", 3)
			defer c.shutdown()

			nc, js := jsClientConnect(t, c.leader())
			defer nc.Close()
			streamCfg := nats.StreamConfig{
				Name:      "TEST",
				Subjects:  []string{"foo"},
				Retention: nats.LimitsPolicy,
				Storage:   st,
				Replicas:  3,
			}

			stream, err := js.AddStream(&streamCfg)
			require_NoError(t, err)

			wg := sync.WaitGroup{}
			ctx, cancel := context.WithCancel(context.Background())
			payload := []byte(strings.Repeat("A", 128))

			wg.Add(1)
			go func() {
				defer wg.Done()
				for range time.NewTicker(10 * time.Millisecond).C {
					select {
					case <-ctx.Done():
						return
					default:
					}
					js.Publish("foo", payload)
				}
			}()
			for i := 0; i < 5; i++ {
				cname := fmt.Sprintf("test_%d", i)
				sub, err := js.PullSubscribe("foo", cname)
				require_NoError(t, err)

				wg.Add(1)
				go func() {
					defer wg.Done()
					for range time.NewTicker(10 * time.Millisecond).C {
						select {
						case <-ctx.Done():
							return
						default:
						}

						msgs, err := sub.Fetch(1)
						if err != nil && errors.Is(err, nats.ErrTimeout) {
							t.Logf("ERROR: %v", err)
						}
						for _, msg := range msgs {
							msg.Ack()
						}
					}
				}()
			}
			// Leave running for a few secs then do the change on a different connection.
			time.Sleep(5 * time.Second)
			nc2, js2 := jsClientConnect(t, c.leader())
			defer nc2.Close()

			// Try updating to interest-based and changing replicas too.
			streamCfg = stream.Config
			streamCfg.Retention = nats.InterestPolicy
			_, err = js2.UpdateStream(&streamCfg)
			require_NoError(t, err)

			// We need to wait for all nodes to have applied the new stream
			// configuration.
			c.waitOnAllCurrent()

			var retention nats.RetentionPolicy
			checkFor(t, 15*time.Second, 500*time.Millisecond, func() error {
				info, err := js2.StreamInfo("TEST", nats.MaxWait(500*time.Millisecond))
				if err != nil {
					return err
				}
				retention = info.Config.Retention
				return nil
			})
			require_Equal(t, retention, nats.InterestPolicy)

			// Cancel and wait for goroutines underneath.
			cancel()
			wg.Wait()
		})
	}
}

func TestJetStreamUsageSyncDeadlock(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"*"},
	})
	require_NoError(t, err)

	sendStreamMsg(t, nc, "foo", "hello")

	// Now purposely mess up the usage that will force a sync.
	// Without the fix this will deadlock.
	jsa := s.getJetStream().lookupAccount(s.GlobalAccount())
	jsa.usageMu.Lock()
	st, ok := jsa.usage[_EMPTY_]
	require_True(t, ok)
	st.local.store = -1000
	jsa.usageMu.Unlock()

	sendStreamMsg(t, nc, "foo", "hello")
}

// https://github.com/nats-io/nats.go/issues/1382
// https://github.com/nats-io/nats-server/issues/4445
func TestJetStreamChangeMaxMessagesPerSubject(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:              "TEST",
		Subjects:          []string{"one.>"},
		MaxMsgsPerSubject: 5,
	})
	require_NoError(t, err)

	for i := 0; i < 10; i++ {
		sendStreamMsg(t, nc, "one.data", "data")
	}

	expectMsgs := func(num int32) error {
		t.Helper()

		var msgs atomic.Int32
		sub, err := js.Subscribe("one.>", func(msg *nats.Msg) {
			msgs.Add(1)
			msg.Ack()
		})
		require_NoError(t, err)
		defer sub.Unsubscribe()

		checkFor(t, 5*time.Second, 100*time.Millisecond, func() error {
			if nm := msgs.Load(); nm != num {
				return fmt.Errorf("expected to get %v messages, got %v instead", num, nm)
			}
			return nil
		})
		return nil
	}

	require_NoError(t, expectMsgs(5))

	js.UpdateStream(&nats.StreamConfig{
		Name:              "TEST",
		Subjects:          []string{"one.>"},
		MaxMsgsPerSubject: 3,
	})

	info, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_True(t, info.Config.MaxMsgsPerSubject == 3)
	require_True(t, info.State.Msgs == 3)

	require_NoError(t, expectMsgs(3))

	for i := 0; i < 10; i++ {
		sendStreamMsg(t, nc, "one.data", "data")
	}

	require_NoError(t, expectMsgs(3))
}

func TestJetStreamSyncInterval(t *testing.T) {
	sd := t.TempDir()
	tmpl := `
		listen: 127.0.0.1:-1
		jetstream: {
			store_dir: %q
			%s
		}`

	for _, test := range []struct {
		name     string
		sync     string
		expected time.Duration
		always   bool
	}{
		{"Default", _EMPTY_, defaultSyncInterval, false},
		{"10s", "sync_interval: 10s", time.Duration(10 * time.Second), false},
		{"Always", "sync_interval: always", defaultSyncInterval, true},
	} {
		t.Run(test.name, func(t *testing.T) {
			conf := createConfFile(t, []byte(fmt.Sprintf(tmpl, sd, test.sync)))
			s, _ := RunServerWithConfig(conf)
			defer s.Shutdown()

			opts := s.getOpts()
			require_True(t, opts.SyncInterval == test.expected)

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := js.AddStream(&nats.StreamConfig{
				Name:     "TEST",
				Subjects: []string{"test.>"},
			})
			require_NoError(t, err)

			mset, err := s.GlobalAccount().lookupStream("TEST")
			require_NoError(t, err)
			fs := mset.store.(*fileStore)
			fs.mu.RLock()
			fsSync := fs.fcfg.SyncInterval
			syncAlways := fs.fcfg.SyncAlways
			fs.mu.RUnlock()
			require_True(t, fsSync == test.expected)
			require_True(t, syncAlways == test.always)
		})
	}
}

func TestJetStreamFilteredSubjectUsesNewConsumerCreateSubject(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, _ := jsClientConnect(t, s)
	defer nc.Close()

	extEndpoint := make(chan *nats.Msg, 1)
	normalEndpoint := make(chan *nats.Msg, 1)

	_, err := nc.ChanSubscribe(JSApiConsumerCreateEx, extEndpoint)
	require_NoError(t, err)

	_, err = nc.ChanSubscribe(JSApiConsumerCreate, normalEndpoint)
	require_NoError(t, err)

	testStreamSource := func(name string, shouldBeExtended bool, ss StreamSource) {
		t.Run(name, func(t *testing.T) {
			req := StreamConfig{
				Name:     name,
				Storage:  MemoryStorage,
				Subjects: []string{fmt.Sprintf("foo.%s", name)},
				Sources:  []*StreamSource{&ss},
			}
			reqJson, err := json.Marshal(req)
			require_NoError(t, err)

			_, err = nc.Request(fmt.Sprintf(JSApiStreamCreateT, name), reqJson, time.Second)
			require_NoError(t, err)

			select {
			case <-time.After(time.Second * 5):
				t.Fatalf("Timed out waiting for receive consumer create")
			case <-extEndpoint:
				if !shouldBeExtended {
					t.Fatalf("Expected normal consumer create, got extended")
				}
			case <-normalEndpoint:
				if shouldBeExtended {
					t.Fatalf("Expected extended consumer create, got normal")
				}
			}
		})
	}

	testStreamSource("OneFilterSubject", true, StreamSource{
		Name:          "source",
		FilterSubject: "bar.>",
	})

	testStreamSource("OneTransform", true, StreamSource{
		Name: "source",
		SubjectTransforms: []SubjectTransformConfig{
			{
				Source:      "bar.one.>",
				Destination: "bar.two.>",
			},
		},
	})

	testStreamSource("TwoTransforms", false, StreamSource{
		Name: "source",
		SubjectTransforms: []SubjectTransformConfig{
			{
				Source:      "bar.one.>",
				Destination: "bar.two.>",
			},
			{
				Source:      "baz.one.>",
				Destination: "baz.two.>",
			},
		},
	})
}

// Make sure when we downgrade history to a smaller number that the account info
// is properly updated and all keys are still accessible.
// There was a bug calculating next first that was not taking into account the dbit slots.
func TestJetStreamKVReductionInHistory(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	startHistory := 4
	kv, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: "TEST", History: uint8(startHistory)})
	require_NoError(t, err)

	numKeys, msg := 1000, bytes.Repeat([]byte("ABC"), 330) // ~1000bytes
	for {
		key := fmt.Sprintf("%X", rand.Intn(numKeys)+1)
		_, err = kv.Put(key, msg)
		require_NoError(t, err)
		status, err := kv.Status()
		require_NoError(t, err)
		if status.Values() >= uint64(startHistory*numKeys) {
			break
		}
	}
	info, err := js.AccountInfo()
	require_NoError(t, err)

	checkAllKeys := func() {
		t.Helper()
		// Make sure we can retrieve all of the keys.
		keys, err := kv.Keys()
		require_NoError(t, err)
		require_Equal(t, len(keys), numKeys)
		for _, key := range keys {
			_, err := kv.Get(key)
			require_NoError(t, err)
		}
	}

	// Quick sanity check.
	checkAllKeys()

	si, err := js.StreamInfo("KV_TEST")
	require_NoError(t, err)
	// Adjust down to history of 1.
	cfg := si.Config
	cfg.MaxMsgsPerSubject = 1
	_, err = js.UpdateStream(&cfg)
	require_NoError(t, err)
	// Make sure the accounting was updated.
	ninfo, err := js.AccountInfo()
	require_NoError(t, err)
	require_True(t, info.Store > ninfo.Store)

	// Make sure all keys still accessible.
	checkAllKeys()
}

func TestJetStreamDirectGetBatch(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo.*"},
	})
	require_NoError(t, err)

	// Add in messages
	for i := 0; i < 333; i++ {
		js.PublishAsync("foo.foo", []byte("HELLO"))
		js.PublishAsync("foo.bar", []byte("WORLD"))
		js.PublishAsync("foo.baz", []byte("AGAIN"))
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	// DirectGet is required for batch. Make sure we error correctly if not enabled.
	mreq := &JSApiMsgGetRequest{Seq: 1, Batch: 10}
	req, _ := json.Marshal(mreq)
	rr, err := nc.Request("$JS.API.STREAM.MSG.GET.TEST", req, time.Second)
	require_NoError(t, err)
	var resp JSApiMsgGetResponse
	json.Unmarshal(rr.Data, &resp)
	require_True(t, resp.Error != nil)
	require_Equal(t, resp.Error.Code, NewJSBadRequestError().Code)

	// Update stream to support direct.
	_, err = js.UpdateStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo.*"},
		AllowDirect: true,
	})
	require_NoError(t, err)

	// Direct subjects.
	sendRequest := func(mreq *JSApiMsgGetRequest) *nats.Subscription {
		t.Helper()
		req, _ := json.Marshal(mreq)
		// We will get multiple responses so can't do normal request.
		reply := nats.NewInbox()
		sub, err := nc.SubscribeSync(reply)
		require_NoError(t, err)
		err = nc.PublishRequest("$JS.API.DIRECT.GET.TEST", reply, req)
		require_NoError(t, err)
		return sub
	}

	// Batch sizes greater than 1 will have a nil message as the end marker.
	checkResponses := func(sub *nats.Subscription, numPendingStart int, expected ...string) {
		t.Helper()
		defer sub.Unsubscribe()
		checkSubsPending(t, sub, len(expected))
		np := numPendingStart
		last := "0"
		for i := 0; i < len(expected); i++ {
			msg, err := sub.NextMsg(10 * time.Millisecond)
			require_NoError(t, err)
			// If expected is _EMPTY_ that signals we expect a EOB marker.
			if subj := expected[i]; subj != _EMPTY_ {
				// Make sure subject is correct.
				require_Equal(t, expected[i], msg.Header.Get(JSSubject))
				// Should have Data field non-zero
				require_True(t, len(msg.Data) > 0)
				// Check we have NumPending and it's correct.
				if np > 0 {
					np--
				}
				require_Equal(t, strconv.Itoa(np), msg.Header.Get(JSNumPending))
				require_Equal(t, last, msg.Header.Get(JSLastSequence))
				last = msg.Header.Get(JSSequence)
			} else {
				// Check for properly formatted EOB marker.
				// Should have no body.
				require_Equal(t, len(msg.Data), 0)
				// We mark status as 204 - No Content
				require_Equal(t, msg.Header.Get("Status"), "204")
				// Check description is EOB
				require_Equal(t, msg.Header.Get("Description"), "EOB")
				// Check we have NumPending and it's correct.
				require_Equal(t, strconv.Itoa(np), msg.Header.Get(JSNumPending))
				require_Equal(t, last, msg.Header.Get(JSLastSequence))
			}
		}
	}

	// Run some simple tests.
	sub := sendRequest(&JSApiMsgGetRequest{Seq: 1, Batch: 2})
	checkResponses(sub, 999, "foo.foo", "foo.bar", _EMPTY_)

	sub = sendRequest(&JSApiMsgGetRequest{Seq: 1, Batch: 3})
	checkResponses(sub, 999, "foo.foo", "foo.bar", "foo.baz", _EMPTY_)

	// Test NextFor works
	sub = sendRequest(&JSApiMsgGetRequest{Seq: 1, Batch: 3, NextFor: "foo.*"})
	checkResponses(sub, 999, "foo.foo", "foo.bar", "foo.baz", _EMPTY_)

	sub = sendRequest(&JSApiMsgGetRequest{Seq: 1, Batch: 3, NextFor: "foo.baz"})
	checkResponses(sub, 333, "foo.baz", "foo.baz", "foo.baz", _EMPTY_)

	// Test stopping early by starting at 997 with only 3 messages.
	sub = sendRequest(&JSApiMsgGetRequest{Seq: 997, Batch: 10, NextFor: "foo.*"})
	checkResponses(sub, 3, "foo.foo", "foo.bar", "foo.baz", _EMPTY_)

	err = js.PurgeStream("TEST")
	require_NoError(t, err)

	// Add in messages
	js.PublishAsync("foo.foo", []byte("HELLO"))
	js.PublishAsync("foo.bar", []byte("WORLD"))
	js.PublishAsync("foo.baz", []byte("AGAIN"))

	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	// Verify that a batch get request starting at a deleted sequence number skips over the deleted messages.
	sub = sendRequest(&JSApiMsgGetRequest{Seq: 1, Batch: 10})
	checkResponses(sub, 3, "foo.foo", "foo.bar", "foo.baz", _EMPTY_)

	// verify that a non-batch direct get to a deleted message returns not found.
	_, err = js.GetMsg("TEST", 1, nats.DirectGet())
	require_Error(t, err, fmt.Errorf("nats: message not found"))

}

func TestJetStreamDirectGetBatchMaxBytes(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo.*"},
		AllowDirect: true,
		Compression: nats.S2Compression,
	})
	require_NoError(t, err)

	msg := bytes.Repeat([]byte("Z"), 512*1024)
	// Add in messages
	for i := 0; i < 333; i++ {
		js.PublishAsync("foo.foo", msg)
		js.PublishAsync("foo.bar", msg)
		js.PublishAsync("foo.baz", msg)
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	sendRequestAndCheck := func(mreq *JSApiMsgGetRequest, numExpected int) {
		t.Helper()
		req, _ := json.Marshal(mreq)
		// We will get multiple responses so can't do normal request.
		reply := nats.NewInbox()
		sub, err := nc.SubscribeSync(reply)
		require_NoError(t, err)
		defer sub.Unsubscribe()
		err = nc.PublishRequest("$JS.API.DIRECT.GET.TEST", reply, req)
		require_NoError(t, err)
		// Make sure we get correct number of responses.
		checkSubsPending(t, sub, numExpected)
	}

	// Total msg size being sent back to us.
	msgSize := len(msg) + len("foo.foo")
	// We should get 1 msg and 1 EOB
	sendRequestAndCheck(&JSApiMsgGetRequest{Seq: 1, Batch: 3, MaxBytes: msgSize}, 2)

	// Test NextFor tracks as well.
	sendRequestAndCheck(&JSApiMsgGetRequest{Seq: 1, NextFor: "foo.bar", Batch: 3, MaxBytes: 2 * msgSize}, 3)

	// Now test no MaxBytes to inherit server max_num_pending.
	expected := (int(s.getOpts().MaxPending) / msgSize) + 1
	sendRequestAndCheck(&JSApiMsgGetRequest{Seq: 1, Batch: 200}, expected+1)
}

func TestJetStreamMsgGetAsOfTime(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo.*"},
		AllowDirect: true,
	})
	require_NoError(t, err)

	sendRequestAndCheck := func(mreq *JSApiMsgGetRequest, seq uint64, eerr error) {
		t.Helper()
		req, _ := json.Marshal(mreq)
		rep, err := nc.Request(fmt.Sprintf(JSApiMsgGetT, "TEST"), req, time.Second)
		require_NoError(t, err)
		var mrep JSApiMsgGetResponse
		err = json.Unmarshal(rep.Data, &mrep)
		require_NoError(t, err)
		if eerr != nil {
			require_Error(t, mrep.ToError(), eerr)
			return
		}
		require_NoError(t, mrep.ToError())
		require_Equal(t, seq, mrep.Message.Sequence)
	}
	t0 := time.Now()

	// Check for conflicting options.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0, LastFor: "foo.1"}, 0, NewJSBadRequestError())
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0, Seq: 1}, 0, NewJSBadRequestError())

	// Nothing exists yet in the stream.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0}, 0, NewJSNoMessageFoundError())

	_, err = js.Publish("foo.1", nil)
	require_NoError(t, err)

	// Try again with t0 and now it will find the first message.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0}, 1, nil)

	t1 := time.Now()
	_, err = js.Publish("foo.2", nil)
	require_NoError(t, err)

	// At t0, first message will still be returned first.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0}, 1, nil)
	// Unless we combine with NextFor...
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0, NextFor: "foo.2"}, 2, nil)

	// At t1 (after first message), the second message will be returned.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t1}, 2, nil)

	t2 := time.Now()
	// t2 is later than the last message so nothing will be found.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t2}, 0, NewJSNoMessageFoundError())
}

func TestJetStreamMsgDirectGetAsOfTime(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo.*"},
		AllowDirect: true,
	})
	require_NoError(t, err)

	sendRequestAndCheck := func(mreq *JSApiMsgGetRequest, seq uint64, eerr string) {
		t.Helper()
		req, _ := json.Marshal(mreq)
		rep, err := nc.Request(fmt.Sprintf(JSDirectMsgGetT, "TEST"), req, time.Second)
		require_NoError(t, err)
		if eerr != "" {
			require_Equal(t, rep.Header.Get("Description"), eerr)
			return
		}

		mseq, err := strconv.ParseUint(rep.Header.Get("Nats-Sequence"), 10, 64)
		require_NoError(t, err)
		require_Equal(t, seq, mseq)
	}
	t0 := time.Now()

	// Check for conflicting options.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0, LastFor: "foo.1"}, 0, "Bad Request")
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0, Seq: 1}, 0, "Bad Request")

	// Nothing exists yet in the stream.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0}, 0, "Message Not Found")

	_, err = js.Publish("foo.1", nil)
	require_NoError(t, err)

	// Try again with t0 and now it will find the first message.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0}, 1, "")

	t1 := time.Now()
	_, err = js.Publish("foo.2", nil)
	require_NoError(t, err)

	// At t0, first message will still be returned first.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0}, 1, "")
	// Unless we combine with NextFor..
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t0, NextFor: "foo.2"}, 2, "")

	// At t1 (after first message), the second message will be returned.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t1}, 2, "")

	t2 := time.Now()
	// t2 is later than the last message so nothing will be found.
	sendRequestAndCheck(&JSApiMsgGetRequest{StartTime: &t2}, 0, "Message Not Found")
}

func TestJetStreamSubjectFilteredPurgeClearsPendingAcks(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo", "bar"},
	})
	require_NoError(t, err)

	for i := 0; i < 5; i++ {
		js.Publish("foo", []byte("OK"))
		js.Publish("bar", []byte("OK"))
	}

	// Note that there are no subject filters here, this is deliberate
	// as previously the purge with filter code was checking for them.
	// We want to prove that unfiltered consumers also get purged.
	ci, err := js.AddConsumer("TEST", &nats.ConsumerConfig{
		Name:          "my_consumer",
		AckPolicy:     nats.AckExplicitPolicy,
		MaxAckPending: 10,
	})
	require_NoError(t, err)
	require_Equal(t, ci.NumPending, 10)
	require_Equal(t, ci.NumAckPending, 0)

	sub, err := js.PullSubscribe(">", "", nats.Bind("TEST", "my_consumer"))
	require_NoError(t, err)

	msgs, err := sub.Fetch(10)
	require_NoError(t, err)
	require_Len(t, len(msgs), 10)

	ci, err = js.ConsumerInfo("TEST", "my_consumer")
	require_NoError(t, err)
	require_Equal(t, ci.NumPending, 0)
	require_Equal(t, ci.NumAckPending, 10)

	require_NoError(t, js.PurgeStream("TEST", &nats.StreamPurgeRequest{
		Subject: "foo",
	}))

	ci, err = js.ConsumerInfo("TEST", "my_consumer")
	require_NoError(t, err)
	require_Equal(t, ci.NumPending, 0)
	require_Equal(t, ci.NumAckPending, 5)

	for i := 0; i < 5; i++ {
		js.Publish("foo", []byte("OK"))
	}
	msgs, err = sub.Fetch(5)
	require_NoError(t, err)
	require_Len(t, len(msgs), 5)

	ci, err = js.ConsumerInfo("TEST", "my_consumer")
	require_NoError(t, err)
	require_Equal(t, ci.NumPending, 0)
	require_Equal(t, ci.NumAckPending, 10)
}

// Helper function for TestJetStreamConsumerPause*, TestJetStreamClusterConsumerPause*, TestJetStreamSuperClusterConsumerPause*
func jsTestPause_CreateOrUpdateConsumer(t *testing.T, nc *nats.Conn, action ConsumerAction, stream string, cc ConsumerConfig) *JSApiConsumerCreateResponse {
	t.Helper()
	j, err := json.Marshal(CreateConsumerRequest{
		Stream: stream,
		Config: cc,
		Action: action,
	})
	require_NoError(t, err)
	subj := fmt.Sprintf("$JS.API.CONSUMER.CREATE.%s.%s", stream, cc.Name)
	m, err := nc.Request(subj, j, time.Second*3)
	require_NoError(t, err)
	var res JSApiConsumerCreateResponse
	require_NoError(t, json.Unmarshal(m.Data, &res))
	require_True(t, res.Config != nil)
	return &res
}

// Helper function for TestJetStreamConsumerPause*, TestJetStreamClusterConsumerPause*, TestJetStreamSuperClusterConsumerPause*
func jsTestPause_PauseConsumer(t *testing.T, nc *nats.Conn, stream, consumer string, deadline time.Time) time.Time {
	t.Helper()
	j, err := json.Marshal(JSApiConsumerPauseRequest{
		PauseUntil: deadline,
	})
	require_NoError(t, err)
	subj := fmt.Sprintf("$JS.API.CONSUMER.PAUSE.%s.%s", stream, consumer)
	msg, err := nc.Request(subj, j, time.Second)
	require_NoError(t, err)
	var res JSApiConsumerPauseResponse
	require_NoError(t, json.Unmarshal(msg.Data, &res))
	return res.PauseUntil
}

func TestJetStreamDirectGetMulti(t *testing.T) {
	cases := []struct {
		name string
		cfg  *nats.StreamConfig
	}{
		{name: "MemoryStore",
			cfg: &nats.StreamConfig{
				Name:        "TEST",
				Subjects:    []string{"foo.*"},
				AllowDirect: true,
				Storage:     nats.MemoryStorage,
			}},
		{name: "FileStore",
			cfg: &nats.StreamConfig{
				Name:        "TEST",
				Subjects:    []string{"foo.*"},
				AllowDirect: true,
			}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {

			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := js.AddStream(c.cfg)
			require_NoError(t, err)

			// Add in messages
			for i := 0; i < 33; i++ {
				js.PublishAsync("foo.foo", []byte(fmt.Sprintf("HELLO-%d", i)))
				js.PublishAsync("foo.bar", []byte(fmt.Sprintf("WORLD-%d", i)))
				js.PublishAsync("foo.baz", []byte(fmt.Sprintf("AGAIN-%d", i)))
			}
			select {
			case <-js.PublishAsyncComplete():
			case <-time.After(5 * time.Second):
				t.Fatalf("Did not receive completion signal")
			}

			// Direct subjects.
			sendRequest := func(mreq *JSApiMsgGetRequest) *nats.Subscription {
				t.Helper()
				req, _ := json.Marshal(mreq)
				// We will get multiple responses so can't do normal request.
				reply := nats.NewInbox()
				sub, err := nc.SubscribeSync(reply)
				require_NoError(t, err)
				err = nc.PublishRequest("$JS.API.DIRECT.GET.TEST", reply, req)
				require_NoError(t, err)
				return sub
			}

			// Subject / Sequence pair
			type p struct {
				subj string
				seq  int
			}
			var eob p

			// Multi-Get will have a nil message as the end marker regardless.
			checkResponses := func(sub *nats.Subscription, numPendingStart int, expected ...p) {
				t.Helper()
				last := "0"
				defer sub.Unsubscribe()
				checkSubsPending(t, sub, len(expected))
				np := numPendingStart
				for i := 0; i < len(expected); i++ {
					msg, err := sub.NextMsg(10 * time.Millisecond)
					require_NoError(t, err)
					// If expected is _EMPTY_ that signals we expect a EOB marker.
					if subj := expected[i].subj; subj != _EMPTY_ {
						// Make sure subject is correct.
						require_Equal(t, subj, msg.Header.Get(JSSubject))
						// Make sure sequence is correct.
						require_Equal(t, strconv.Itoa(expected[i].seq), msg.Header.Get(JSSequence))
						// Should have Data field non-zero
						require_True(t, len(msg.Data) > 0)
						// Check we have NumPending and it's correct.
						if np > 0 {
							np--
						}
						require_Equal(t, strconv.Itoa(np), msg.Header.Get(JSNumPending))
						require_Equal(t, last, msg.Header.Get(JSLastSequence))
						last = msg.Header.Get(JSSequence)
					} else {
						// Check for properly formatted EOB marker.
						// Should have no body.
						require_Equal(t, len(msg.Data), 0)
						// We mark status as 204 - No Content
						require_Equal(t, msg.Header.Get("Status"), "204")
						// Check description is EOB
						require_Equal(t, msg.Header.Get("Description"), "EOB")
						// Check we have NumPending and it's correct.
						require_Equal(t, strconv.Itoa(np), msg.Header.Get(JSNumPending))
						require_Equal(t, last, msg.Header.Get(JSLastSequence))
					}
				}
			}

			sub := sendRequest(&JSApiMsgGetRequest{MultiLastFor: []string{"foo.*"}})
			checkResponses(sub, 3, p{"foo.foo", 97}, p{"foo.bar", 98}, p{"foo.baz", 99}, eob)
			// Check with UpToSeq
			sub = sendRequest(&JSApiMsgGetRequest{MultiLastFor: []string{"foo.*"}, UpToSeq: 3})
			checkResponses(sub, 3, p{"foo.foo", 1}, p{"foo.bar", 2}, p{"foo.baz", 3}, eob)
			// check last header sequence number is correct
			sub = sendRequest(&JSApiMsgGetRequest{MultiLastFor: []string{"foo.foo", "foo.baz"}})
			checkResponses(sub, 2, p{"foo.foo", 97}, p{"foo.baz", 99}, eob)
			// Test No Results.
			sub = sendRequest(&JSApiMsgGetRequest{MultiLastFor: []string{"bar.*"}})
			checkSubsPending(t, sub, 1)
			msg, err := sub.NextMsg(10 * time.Millisecond)
			require_NoError(t, err)
			// Check for properly formatted No Results.
			// Should have no body.
			require_Equal(t, len(msg.Data), 0)
			// We mark status as 204 - No Content
			require_Equal(t, msg.Header.Get("Status"), "404")
			// Check description is No Results
			require_Equal(t, msg.Header.Get("Description"), "No Results")
		})
	}
}

func TestJetStreamDirectGetMultiUpToTime(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo.*"},
		AllowDirect: true,
	})
	require_NoError(t, err)

	js.Publish("foo.foo", []byte("1"))
	js.Publish("foo.bar", []byte("1"))
	js.Publish("foo.baz", []byte("1"))
	start := time.Now()
	time.Sleep(time.Second)
	js.Publish("foo.foo", []byte("2"))
	js.Publish("foo.bar", []byte("2"))
	js.Publish("foo.baz", []byte("2"))
	mid := time.Now()
	time.Sleep(time.Second)
	js.Publish("foo.foo", []byte("3"))
	js.Publish("foo.bar", []byte("3"))
	js.Publish("foo.baz", []byte("3"))
	end := time.Now()

	// Direct subjects.
	sendRequest := func(mreq *JSApiMsgGetRequest) *nats.Subscription {
		t.Helper()
		req, _ := json.Marshal(mreq)
		// We will get multiple responses so can't do normal request.
		reply := nats.NewInbox()
		sub, err := nc.SubscribeSync(reply)
		require_NoError(t, err)
		err = nc.PublishRequest("$JS.API.DIRECT.GET.TEST", reply, req)
		require_NoError(t, err)
		return sub
	}

	checkResponses := func(sub *nats.Subscription, val string, expected ...string) {
		t.Helper()
		defer sub.Unsubscribe()
		checkSubsPending(t, sub, len(expected))
		for i := 0; i < len(expected); i++ {
			msg, err := sub.NextMsg(10 * time.Millisecond)
			require_NoError(t, err)
			// If expected is _EMPTY_ that signals we expect a EOB marker.
			if subj := expected[i]; subj != _EMPTY_ {
				// Make sure subject is correct.
				require_Equal(t, subj, msg.Header.Get(JSSubject))
				// Should have Data field non-zero
				require_True(t, len(msg.Data) > 0)
				// Make sure the value matches.
				require_Equal(t, string(msg.Data), val)
			}
		}
	}

	// Make sure you can't set both.
	sub := sendRequest(&JSApiMsgGetRequest{Seq: 1, MultiLastFor: []string{"foo.*"}, UpToSeq: 3, UpToTime: &start})
	checkSubsPending(t, sub, 1)
	msg, err := sub.NextMsg(10 * time.Millisecond)
	require_NoError(t, err)
	// Check for properly formatted No Results.
	// Should have no body.
	require_Equal(t, len(msg.Data), 0)
	// We mark status as 204 - No Content
	require_Equal(t, msg.Header.Get("Status"), "408")
	// Check description is No Results
	require_Equal(t, msg.Header.Get("Description"), "Bad Request")

	// Valid responses.
	sub = sendRequest(&JSApiMsgGetRequest{Seq: 1, MultiLastFor: []string{"foo.*"}, UpToTime: &start})
	checkResponses(sub, "1", "foo.foo", "foo.bar", "foo.baz", _EMPTY_)

	sub = sendRequest(&JSApiMsgGetRequest{Seq: 1, MultiLastFor: []string{"foo.*"}, UpToTime: &mid})
	checkResponses(sub, "2", "foo.foo", "foo.bar", "foo.baz", _EMPTY_)

	sub = sendRequest(&JSApiMsgGetRequest{Seq: 1, MultiLastFor: []string{"foo.*"}, UpToTime: &end})
	checkResponses(sub, "3", "foo.foo", "foo.bar", "foo.baz", _EMPTY_)
}

func TestJetStreamDirectGetMultiMaxAllowed(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo.*"},
		AllowDirect: true,
	})
	require_NoError(t, err)

	// from stream.go - const maxAllowedResponses = 1024, so max sure > 1024
	// Add in messages
	for i := 1; i <= 1025; i++ {
		js.PublishAsync(fmt.Sprintf("foo.%d", i), []byte("OK"))
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}

	req, _ := json.Marshal(&JSApiMsgGetRequest{Seq: 1, MultiLastFor: []string{"foo.*"}})
	msg, err := nc.Request("$JS.API.DIRECT.GET.TEST", req, time.Second)
	require_NoError(t, err)

	// Check for properly formatted Too Many Results error.
	// Should have no body.
	require_Equal(t, len(msg.Data), 0)
	// We mark status as 413 - Too Many Results
	require_Equal(t, msg.Header.Get("Status"), "413")
	// Check description is No Results
	require_Equal(t, msg.Header.Get("Description"), "Too Many Results")
}

func TestJetStreamDirectGetMultiPaging(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo.*"},
		AllowDirect: true,
	})
	require_NoError(t, err)

	// We will queue up 500 messages, each 512k big and request them for a multi-get.
	// This will not hit the max allowed limit of 1024, but will bump up against max bytes and only return partial results.
	// We want to make sure we can pick up where we left off.

	// Add in messages
	data, sent := bytes.Repeat([]byte("Z"), 512*1024), 500
	for i := 1; i <= sent; i++ {
		js.PublishAsync(fmt.Sprintf("foo.%d", i), data)
	}
	select {
	case <-js.PublishAsyncComplete():
	case <-time.After(5 * time.Second):
		t.Fatalf("Did not receive completion signal")
	}
	// Wait for all replicas to be correct.
	time.Sleep(time.Second)

	// Direct subjects.
	sendRequest := func(mreq *JSApiMsgGetRequest) *nats.Subscription {
		t.Helper()
		req, _ := json.Marshal(mreq)
		// We will get multiple responses so can't do normal request.
		reply := nats.NewInbox()
		sub, err := nc.SubscribeSync(reply)
		require_NoError(t, err)
		err = nc.PublishRequest("$JS.API.DIRECT.GET.TEST", reply, req)
		require_NoError(t, err)
		return sub
	}

	// Setup variables that control procesPartial
	start, seq, np, b, bsz := 1, 1, sent, 0, 128

	processPartial := func(expected int) {
		t.Helper()
		sub := sendRequest(&JSApiMsgGetRequest{Seq: uint64(start), Batch: b, MultiLastFor: []string{"foo.*"}})
		checkSubsPending(t, sub, expected)
		// Check partial.
		// We should receive seqs seq-(seq+bsz-1)
		for ; seq < start+(expected-1); seq++ {
			msg, err := sub.NextMsg(10 * time.Millisecond)
			require_NoError(t, err)
			// Make sure sequence is correct.
			require_Equal(t, strconv.Itoa(int(seq)), msg.Header.Get(JSSequence))
			// Check we have NumPending and it's correct.
			if np > 0 {
				np--
			}
			require_Equal(t, strconv.Itoa(np), msg.Header.Get(JSNumPending))
		}
		// Now check EOB
		msg, err := sub.NextMsg(10 * time.Millisecond)
		require_NoError(t, err)
		// We mark status as 204 - No Content
		require_Equal(t, msg.Header.Get("Status"), "204")
		// Check description is EOB
		require_Equal(t, msg.Header.Get("Description"), "EOB")
		// Check we have NumPending and it's correct.
		require_Equal(t, strconv.Itoa(np), msg.Header.Get(JSNumPending))
		// Check we have LastSequence and it's correct.
		require_Equal(t, strconv.Itoa(seq-1), msg.Header.Get(JSLastSequence))
		// Check we have UpToSequence and it's correct.
		require_Equal(t, strconv.Itoa(sent), msg.Header.Get(JSUpToSequence))
		// Update start
		start = seq
	}

	processPartial(bsz + 1) // 128 + EOB
	processPartial(bsz + 1) // 128 + EOB
	processPartial(bsz + 1) // 128 + EOB
	// Last one will be a partial block.
	processPartial(116 + 1)

	// Now reset and test that batch is honored as well.
	start, seq, np, b = 1, 1, sent, 100
	for i := 0; i < 5; i++ {
		processPartial(b + 1) // 100 + EOB
	}
}

// https://github.com/nats-io/nats-server/issues/4878
func TestJetStreamInterestStreamConsumerFilterEdit(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "INTEREST",
		Retention: nats.InterestPolicy,
		Subjects:  []string{"interest.>"},
	})
	require_NoError(t, err)

	_, err = js.AddConsumer("INTEREST", &nats.ConsumerConfig{
		Durable:       "C0",
		FilterSubject: "interest.>",
		AckPolicy:     nats.AckExplicitPolicy,
	})
	require_NoError(t, err)

	for i := 0; i < 10; i++ {
		_, err = js.Publish(fmt.Sprintf("interest.%d", i), []byte(strconv.Itoa(i)))
		require_NoError(t, err)
	}

	// we check we got 10 messages
	nfo, err := js.StreamInfo("INTEREST")
	require_NoError(t, err)
	if nfo.State.Msgs != 10 {
		t.Fatalf("expected 10 messages got %d", nfo.State.Msgs)
	}

	// now we lower the consumer interest from all subjects to 1,
	// then check the stream state and check if interest behavior still works
	_, err = js.UpdateConsumer("INTEREST", &nats.ConsumerConfig{
		Durable:       "C0",
		FilterSubject: "interest.1",
		AckPolicy:     nats.AckExplicitPolicy,
	})
	require_NoError(t, err)

	// we should now have only one message left
	nfo, err = js.StreamInfo("INTEREST")
	require_NoError(t, err)
	if nfo.State.Msgs != 1 {
		t.Fatalf("expected 1 message got %d", nfo.State.Msgs)
	}
}

// https://github.com/nats-io/nats-server/issues/5383
func TestJetStreamInterestStreamWithFilterSubjectsConsumer(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "INTEREST",
		Retention: nats.InterestPolicy,
		Subjects:  []string{"interest.>"},
	})
	require_NoError(t, err)

	_, err = js.AddConsumer("INTEREST", &nats.ConsumerConfig{
		Durable:        "C",
		FilterSubjects: []string{"interest.a", "interest.b"},
		AckPolicy:      nats.AckExplicitPolicy,
	})
	require_NoError(t, err)

	for _, sub := range []string{"interest.a", "interest.b", "interest.c"} {
		_, err = js.Publish(sub, nil)
		require_NoError(t, err)
	}

	// we check we got 2 messages, interest.c doesn't have interest
	nfo, err := js.StreamInfo("INTEREST")
	require_NoError(t, err)
	if nfo.State.Msgs != 2 {
		t.Fatalf("expected 2 messages got %d", nfo.State.Msgs)
	}
}

func TestJetStreamAckAllWithLargeFirstSequenceAndNoAckFloor(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo.>"},
	})
	require_NoError(t, err)

	// Set first sequence to something very big here. This shows the issue with AckAll the
	// first time it is called and existing ack floor is 0.
	err = js.PurgeStream("TEST", &nats.StreamPurgeRequest{Sequence: 10_000_000_000})
	require_NoError(t, err)

	// Now add in 100 msgs
	for i := 0; i < 100; i++ {
		js.Publish("foo.bar", []byte("hello"))
	}

	ss, err := js.PullSubscribe("foo.*", "C1", nats.AckAll())
	require_NoError(t, err)
	msgs, err := ss.Fetch(10, nats.MaxWait(100*time.Millisecond))
	require_NoError(t, err)
	require_Equal(t, len(msgs), 10)

	start := time.Now()
	msgs[9].AckSync()
	if elapsed := time.Since(start); elapsed > 250*time.Millisecond {
		t.Fatalf("AckSync took too long %v", elapsed)
	}

	// Make sure next fetch works right away with low timeout.
	msgs, err = ss.Fetch(10, nats.MaxWait(100*time.Millisecond))
	require_NoError(t, err)
	require_Equal(t, len(msgs), 10)

	_, err = js.StreamInfo("TEST", nats.MaxWait(250*time.Millisecond))
	require_NoError(t, err)

	// Now make sure that if we ack in the middle, meaning we still have ack pending,
	// that we do the right thing as well.
	ss, err = js.PullSubscribe("foo.*", "C2", nats.AckAll())
	require_NoError(t, err)
	msgs, err = ss.Fetch(10, nats.MaxWait(100*time.Millisecond))
	require_NoError(t, err)
	require_Equal(t, len(msgs), 10)

	start = time.Now()
	msgs[5].AckSync()
	if elapsed := time.Since(start); elapsed > 250*time.Millisecond {
		t.Fatalf("AckSync took too long %v", elapsed)
	}

	// Make sure next fetch works right away with low timeout.
	msgs, err = ss.Fetch(10, nats.MaxWait(100*time.Millisecond))
	require_NoError(t, err)
	require_Equal(t, len(msgs), 10)

	_, err = js.StreamInfo("TEST", nats.MaxWait(250*time.Millisecond))
	require_NoError(t, err)
}

func TestJetStreamAckAllWithLargeFirstSequenceAndNoAckFloorWithInterestPolicy(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "TEST",
		Subjects:  []string{"foo.>"},
		Retention: nats.InterestPolicy,
	})
	require_NoError(t, err)

	// Set first sequence to something very big here. This shows the issue with AckAll the
	// first time it is called and existing ack floor is 0.
	err = js.PurgeStream("TEST", &nats.StreamPurgeRequest{Sequence: 10_000_000_000})
	require_NoError(t, err)

	ss, err := js.PullSubscribe("foo.*", "C1", nats.AckAll())
	require_NoError(t, err)

	// Now add in 100 msgs
	for i := 0; i < 100; i++ {
		js.Publish("foo.bar", []byte("hello"))
	}

	msgs, err := ss.Fetch(10, nats.MaxWait(100*time.Millisecond))
	require_NoError(t, err)
	require_Equal(t, len(msgs), 10)

	start := time.Now()
	msgs[5].AckSync()
	if elapsed := time.Since(start); elapsed > 250*time.Millisecond {
		t.Fatalf("AckSync took too long %v", elapsed)
	}

	// We are testing for run away loops acking messages in the stream that are not there.
	_, err = js.StreamInfo("TEST", nats.MaxWait(100*time.Millisecond))
	require_NoError(t, err)
}

// Allow streams with $JS or $SYS prefixes for audit purposes but require no pub ack be set.
func TestJetStreamAuditStreams(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	jsOverlap := errors.New("subjects that overlap with jetstream api require no-ack to be true")
	sysOverlap := errors.New("subjects that overlap with system api require no-ack to be true")

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"$JS.>"},
	})
	require_Error(t, err, NewJSStreamInvalidConfigError(jsOverlap))

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"$JS.API.>"},
	})
	require_Error(t, err, NewJSStreamInvalidConfigError(jsOverlap))

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"$JSC.>"},
	})
	require_Error(t, err, NewJSStreamInvalidConfigError(jsOverlap))

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"$SYS.>"},
	})
	require_Error(t, err, NewJSStreamInvalidConfigError(sysOverlap))

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{">"},
	})
	require_Error(t, err, NewJSStreamInvalidConfigError(errors.New("capturing all subjects requires no-ack to be true")))

	// These should all be ok if no pub ack.
	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST1",
		Subjects: []string{"$JS.>"},
		NoAck:    true,
	})
	require_NoError(t, err)

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST2",
		Subjects: []string{"$JSC.>"},
		NoAck:    true,
	})
	require_NoError(t, err)

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST3",
		Subjects: []string{"$SYS.>"},
		NoAck:    true,
	})
	require_NoError(t, err)

	// Since prior behavior did allow $JS.EVENT to be captured without no-ack, these might break
	// on a server upgrade so make sure they still work ok without --no-ack.

	// To avoid overlap error.
	err = js.DeleteStream("TEST1")
	require_NoError(t, err)

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST4",
		Subjects: []string{"$JS.EVENT.>"},
	})
	require_NoError(t, err)

	// Also allow $SYS.ACCOUNT to be captured without no-ack, these also might break
	// on a server upgrade so make sure they still work ok without --no-ack.

	// To avoid overlap error.
	err = js.DeleteStream("TEST3")
	require_NoError(t, err)

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST5",
		Subjects: []string{"$SYS.ACCOUNT.>"},
	})
	require_NoError(t, err)

	// We will test handling of ">" on a cluster here.
	// Specific test for capturing everything which will require both no-ack and replicas of 1.
	c := createJetStreamClusterExplicit(t, "R3S", 3)
	defer c.shutdown()

	nc, js = jsClientConnect(t, c.randomServer())
	defer nc.Close()

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{">"},
	})
	require_Error(t, err, NewJSStreamInvalidConfigError(errors.New("capturing all subjects requires no-ack to be true")))

	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{">"},
		Replicas: 3,
		NoAck:    true,
	})
	require_Error(t, err, NewJSStreamInvalidConfigError(errors.New("capturing all subjects requires replicas of 1")))

	// Ths should work ok.
	_, err = js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{">"},
		Replicas: 1,
		NoAck:    true,
	})
	require_NoError(t, err)
}

// https://github.com/nats-io/nats-server/issues/5570
func TestJetStreamBadSubjectMappingStream(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	// Client for API requests.
	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{Name: "test"})
	require_NoError(t, err)

	_, err = js.UpdateStream(&nats.StreamConfig{
		Name: "test",
		Sources: []*nats.StreamSource{
			{
				Name: "mapping",
				SubjectTransforms: []nats.SubjectTransformConfig{
					{
						Source:      "events.*",
						Destination: "events.{{wildcard(1)}}{{split(3,1)}}",
					},
				},
			},
		},
	})
	require_Error(t, err, NewJSStreamUpdateError(errors.New("nats: source transform: invalid mapping destination: too many arguments passed to the function in {{wildcard(1)}}{{split(3,1)}}")))

	_, err = js.UpdateStream(&nats.StreamConfig{
		Name: "test",
		Sources: []*nats.StreamSource{
			{
				Name: "mapping",
				SubjectTransforms: []nats.SubjectTransformConfig{
					{
						Source:      "events.>.*",
						Destination: "events.{{split(1,1)}}",
					},
				},
			},
		},
	})
	require_Error(t, err, NewJSStreamUpdateError(errors.New("nats: source transform source: invalid subject events.>.*")))

	_, err = js.UpdateStream(&nats.StreamConfig{
		Name: "test",
		Mirror: &nats.StreamSource{
			Name: "mapping",
			SubjectTransforms: []nats.SubjectTransformConfig{
				{
					Source:      "events.*",
					Destination: "events.{{split(3,1)}}",
				},
			},
		},
	})
	require_Error(t, err, NewJSStreamUpdateError(errors.New("nats: mirror transform: invalid mapping destination: wildcard index out of range in {{split(3,1)}}: [3]")))

	_, err = js.UpdateStream(&nats.StreamConfig{
		Name: "test",
		Mirror: &nats.StreamSource{
			Name: "mapping",
			SubjectTransforms: []nats.SubjectTransformConfig{
				{
					Source:      "events.>.*",
					Destination: "events.{{split(1,1)}}",
				},
			},
		},
	})
	require_Error(t, err, NewJSStreamUpdateError(errors.New("nats: mirror transform source: invalid subject events.>.*")))

	_, err = js.UpdateStream(&nats.StreamConfig{
		Name: "test",
		SubjectTransform: &nats.SubjectTransformConfig{
			Source:      "events.*",
			Destination: "events.{{split(3,1)}}",
		},
	})
	require_Error(t, err, NewJSStreamUpdateError(errors.New("nats: stream transform: invalid mapping destination: wildcard index out of range in {{split(3,1)}}: [3]")))

	_, err = js.UpdateStream(&nats.StreamConfig{
		Name: "test",
		SubjectTransform: &nats.SubjectTransformConfig{
			Source:      "events.>.*",
			Destination: "events.{{split(1,1)}}",
		},
	})
	require_Error(t, err, NewJSStreamUpdateError(errors.New("nats: stream transform source: invalid subject events.>.*")))
}

func TestJetStreamInterestStreamWithDuplicateMessages(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	cfg := &nats.StreamConfig{
		Name:      "INTEREST",
		Subjects:  []string{"interest"},
		Replicas:  1,
		Retention: nats.InterestPolicy,
	}
	_, err := js.AddStream(cfg)
	require_NoError(t, err)

	// Publishing the first time should give a sequence, even when there's no interest.
	pa, err := js.Publish("interest", nil, nats.MsgId("dedupe"))
	require_NoError(t, err)
	require_Equal(t, pa.Sequence, 1)
	require_Equal(t, pa.Duplicate, false)

	// Publishing a duplicate with no interest should return the same sequence as above.
	pa, err = js.Publish("interest", nil, nats.MsgId("dedupe"))
	require_NoError(t, err)
	require_Equal(t, pa.Sequence, 1)
	require_Equal(t, pa.Duplicate, true)
}

func TestJetStreamStreamCreatePedanticMode(t *testing.T) {
	cfgFmt := []byte(fmt.Sprintf(`
        jetstream: {
            enabled: true
            max_file_store: 100MB
            store_dir: %s
            limits: {duplicate_window: "1m", max_request_batch: 250}
        }
        accounts: {
            myacc: {
                jetstream: enabled
                users: [ { user: user, password: pass  } ]
            }
        }
        no_auth_user: user
	`, t.TempDir()))

	conf := createConfFile(t, cfgFmt)
	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, _ := jsClientConnect(t, s)
	defer nc.Close()

	tests := []struct {
		name      string
		cfg       StreamConfigRequest
		shouldErr bool
		update    bool
	}{
		{
			name: "too_high_duplicate",
			cfg: StreamConfigRequest{
				StreamConfig: StreamConfig{
					Name:       "TEST",
					MaxAge:     time.Minute,
					Duplicates: time.Hour,
					Storage:    FileStorage,
				},
				Pedantic: true,
			},
			shouldErr: true,
		},
		{
			name: "duplicate_over_limits",
			cfg: StreamConfigRequest{
				StreamConfig: StreamConfig{
					Name:       "TEST",
					MaxAge:     time.Hour * 60,
					Duplicates: time.Hour,
					Storage:    FileStorage,
				},
				Pedantic: false,
			},
			shouldErr: true,
		},
		{
			name: "duplicate_window_within_limits",
			cfg: StreamConfigRequest{
				StreamConfig: StreamConfig{
					Name:       "TEST",
					MaxAge:     time.Hour * 60,
					Duplicates: time.Second * 30,
					Storage:    FileStorage,
				},
				Pedantic: false,
			},
			shouldErr: false,
		},
		{
			name: "update_too_high_duplicate",
			cfg: StreamConfigRequest{
				StreamConfig: StreamConfig{
					Name:       "TEST",
					MaxAge:     time.Minute,
					Duplicates: time.Hour,
					Storage:    FileStorage,
				},
				Pedantic: true,
			},
			update:    true,
			shouldErr: true,
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if !test.update {
				_, err := addStreamPedanticWithError(t, nc, &test.cfg)
				require_True(t, (err != nil) == test.shouldErr)
			} else {
				_, err := updateStreamPedanticWithError(t, nc, &test.cfg)
				require_True(t, (err != nil) == test.shouldErr)
			}
		})
	}
}

func TestJetStreamStrictMode(t *testing.T) {
	cfgFmt := []byte(fmt.Sprintf(`
		jetstream: {
			strict: true
			enabled: true
			max_file_store: 100MB
			store_dir: %s
			limits: {duplicate_window: "1m", max_request_batch: 250}
		}
	`, t.TempDir()))
	conf := createConfFile(t, cfgFmt)
	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, err := nats.Connect(s.ClientURL())
	if err != nil {
		t.Fatalf("Error connecting to NATS: %v", err)
	}
	defer nc.Close()

	tests := []struct {
		name        string
		subject     string
		payload     []byte
		expectedErr string
	}{
		{
			name:        "Stream Create",
			subject:     "$JS.API.STREAM.CREATE.TEST_STREAM",
			payload:     []byte(`{"name":"TEST_STREAM","subjects":["test.>"],"extra_field":"unexpected"}`),
			expectedErr: "invalid JSON",
		},
		{
			name:        "Stream Update",
			subject:     "$JS.API.STREAM.UPDATE.TEST_STREAM",
			payload:     []byte(`{"name":"TEST_STREAM","subjects":["test.>"],"extra_field":"unexpected"}`),
			expectedErr: "invalid JSON",
		},
		{
			name:        "Stream Delete",
			subject:     "$JS.API.STREAM.DELETE.TEST_STREAM",
			payload:     []byte(`{"extra_field":"unexpected"}`),
			expectedErr: "expected an empty request payload",
		},
		{
			name:        "Stream Info",
			subject:     "$JS.API.STREAM.INFO.TEST_STREAM",
			payload:     []byte(`{"extra_field":"unexpected"}`),
			expectedErr: "invalid JSON",
		},
		{
			name:        "Consumer Create",
			subject:     "$JS.API.CONSUMER.CREATE.TEST_STREAM.TEST_CONSUMER",
			payload:     []byte(`{"durable_name":"TEST_CONSUMER","ack_policy":"explicit","extra_field":"unexpected"}`),
			expectedErr: "invalid JSON",
		},
		{
			name:        "Consumer Delete",
			subject:     "$JS.API.CONSUMER.DELETE.TEST_STREAM.TEST_CONSUMER",
			payload:     []byte(`{"extra_field":"unexpected"}`),
			expectedErr: "expected an empty request payload",
		},
		{
			name:        "Consumer Info",
			subject:     "$JS.API.CONSUMER.INFO.TEST_STREAM.TEST_CONSUMER",
			payload:     []byte(`{"extra_field":"unexpected"}`),
			expectedErr: "expected an empty request payload",
		},
		{
			name:        "Stream List",
			subject:     "$JS.API.STREAM.LIST",
			payload:     []byte(`{"extra_field":"unexpected"}`),
			expectedErr: "invalid JSON",
		},
		{
			name:        "Consumer List",
			subject:     "$JS.API.CONSUMER.LIST.TEST_STREAM",
			payload:     []byte(`{"extra_field":"unexpected"}`),
			expectedErr: "invalid JSON",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			resp, err := nc.Request(tt.subject, tt.payload, time.Second*10)
			if err != nil {
				t.Fatalf("Request failed: %v", err)
			}

			var apiResp ApiResponse = ApiResponse{}

			if err := json.Unmarshal(resp.Data, &apiResp); err != nil {
				t.Fatalf("Error unmarshalling response: %v", err)
			}

			require_NotNil(t, apiResp.Error.Description)
			require_Contains(t, apiResp.Error.Description, tt.expectedErr)
		})
	}
}

func addConsumerWithError(t *testing.T, nc *nats.Conn, cfg *CreateConsumerRequest) (*ConsumerInfo, *ApiError) {
	t.Helper()
	req, err := json.Marshal(cfg)
	require_NoError(t, err)
	rmsg, err := nc.Request(fmt.Sprintf(JSApiDurableCreateT, cfg.Stream, cfg.Config.Durable), req, 5*time.Second)

	require_NoError(t, err)
	var resp JSApiConsumerCreateResponse
	err = json.Unmarshal(rmsg.Data, &resp)
	require_NoError(t, err)
	if resp.Type != JSApiConsumerCreateResponseType {
		t.Fatalf("Invalid response type %s expected %s", resp.Type, JSApiConsumerCreateResponseType)
	}
	return resp.ConsumerInfo, resp.Error
}

func TestJetStreamSourceRemovalAndReAdd(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// The source stream.
	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "SRC",
		Subjects: []string{"foo.*"},
	})
	require_NoError(t, err)

	// The stream that sources.
	_, err = js.AddStream(&nats.StreamConfig{
		Name: "TEST",
		Sources: []*nats.StreamSource{{
			Name: "SRC",
		}},
	})
	require_NoError(t, err)

	// Now add in 10 msgs.
	for i := 0; i < 10; i++ {
		_, err := js.Publish(fmt.Sprintf("foo.%d", i), []byte("test"))
		require_NoError(t, err)
	}

	// Make sure we have 10 msgs in TEST.
	checkFor(t, time.Second, 200*time.Millisecond, func() error {
		si, err := js.StreamInfo("TEST")
		require_NoError(t, err)
		if si.State.Msgs == 10 {
			return nil
		}
		return fmt.Errorf("Do not have all msgs yet, %d of 10", si.State.Msgs)
	})

	// Now update the TEST stream to no longer source.
	_, err = js.UpdateStream(&nats.StreamConfig{
		Name: "TEST",
	})
	require_NoError(t, err)

	// Now add in 10 more msgs.
	for i := 0; i < 10; i++ {
		_, err := js.Publish(fmt.Sprintf("foo.%d", i+10), []byte("test"))
		require_NoError(t, err)
	}
	// Make sure we are still stuck at 10 for TEST.
	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 10)

	// Now re-add the source to our stream.
	_, err = js.UpdateStream(&nats.StreamConfig{
		Name: "TEST",
		Sources: []*nats.StreamSource{{
			Name: "SRC",
		}},
	})
	require_NoError(t, err)

	// Make sure we have 20 msgs now.
	// Make sure we have 10 msgs in TEST.
	checkFor(t, time.Second, 200*time.Millisecond, func() error {
		si, err := js.StreamInfo("TEST")
		require_NoError(t, err)
		if si.State.Msgs == 20 {
			return nil
		}
		return fmt.Errorf("Do not have all msgs yet, %d of 20", si.State.Msgs)
	})

	// Check that we get what we want in the stream.
	sub, err := js.PullSubscribe("foo.*", "d")
	require_NoError(t, err)

	msgs, err := sub.Fetch(20)
	require_NoError(t, err)
	require_Equal(t, len(msgs), 20)

	for i, m := range msgs {
		require_Equal(t, m.Subject, fmt.Sprintf("foo.%d", i))
	}
}

func TestJetStreamRateLimitHighStreamIngest(t *testing.T) {
	cfgFmt := []byte(fmt.Sprintf(`
        jetstream: {
            enabled: true
            store_dir: %s
            max_buffered_size: 1kb
            max_buffered_msgs: 1
        }
       `, t.TempDir()))

	conf := createConfFile(t, cfgFmt)
	s, opts := RunServerWithConfig(conf)
	defer s.Shutdown()

	require_Equal(t, opts.StreamMaxBufferedSize, 1024)
	require_Equal(t, opts.StreamMaxBufferedMsgs, 1)

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"test"},
	})
	require_NoError(t, err)

	// Create a reply inbox that we can await API requests on.
	// This is instead of using nc.Request().
	inbox := nc.NewRespInbox()
	resp := make(chan *nats.Msg, 1000)
	_, err = nc.ChanSubscribe(inbox, resp)
	require_NoError(t, err)

	// Publish a large number of messages using Core NATS withou
	// waiting for the responses from the API.
	msg := &nats.Msg{
		Subject: "test",
		Reply:   inbox,
	}
	for i := 0; i < 1000; i++ {
		require_NoError(t, nc.PublishMsg(msg))
	}

	// Now sort through the API responses. We're looking for one
	// that tells us that we were rate-limited. If we don't find
	// one then we fail the test.
	var rateLimited bool
	for i, msg := 0, <-resp; i < 1000; i, msg = i+1, <-resp {
		if msg.Header.Get("Status") == "429" {
			rateLimited = true
			break
		}
	}
	require_True(t, rateLimited)
}

func TestJetStreamRateLimitHighStreamIngestDefaults(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"test"},
	})
	require_NoError(t, err)

	stream, err := s.globalAccount().lookupStream("TEST")
	require_NoError(t, err)

	require_Equal(t, stream.msgs.mlen, streamDefaultMaxQueueMsgs)
	require_Equal(t, stream.msgs.msz, streamDefaultMaxQueueBytes)
}

func TestJetStreamStreamConfigClone(t *testing.T) {
	cfg := &StreamConfig{
		Name:             "name",
		Placement:        &Placement{Cluster: "placement", Tags: []string{"tag"}},
		Mirror:           &StreamSource{Name: "mirror"},
		Sources:          []*StreamSource{&StreamSource{Name: "source"}},
		SubjectTransform: &SubjectTransformConfig{Source: "source", Destination: "dest"},
		RePublish:        &RePublish{Source: "source", Destination: "dest", HeadersOnly: false},
		Metadata:         make(map[string]string),
	}

	// Copy should be complete.
	clone := cfg.clone()
	require_True(t, reflect.DeepEqual(cfg, clone))

	// Changing fields should not update the original.
	clone.Placement.Cluster = "diff"
	require_False(t, reflect.DeepEqual(cfg.Placement, clone.Placement))

	clone.Mirror.Name = "diff"
	require_False(t, reflect.DeepEqual(cfg.Mirror, clone.Mirror))

	clone.Sources[0].Name = "diff"
	require_False(t, reflect.DeepEqual(cfg.Sources, clone.Sources))

	clone.SubjectTransform.Source = "diff"
	require_False(t, reflect.DeepEqual(cfg.SubjectTransform, clone.SubjectTransform))

	clone.RePublish.Source = "diff"
	require_False(t, reflect.DeepEqual(cfg.RePublish, clone.RePublish))

	clone.Metadata["key"] = "value"
	require_False(t, reflect.DeepEqual(cfg.Metadata, clone.Metadata))
}

func TestIsJSONObjectOrArray(t *testing.T) {
	tests := []struct {
		name  string
		data  []byte
		valid bool
	}{
		{"empty", []byte{}, false},
		{"empty_object", []byte("{}"), true},
		{"empty object, not trimmed", []byte("\t\n\r{ }"), true},
		{"empty_array", []byte("[]"), true},
		{"empty array, not trimmed", []byte("\t\n\r[ ]"), true},
		// This is a valid JSON, but it's not a JSON object or array.
		{"empty_string", []byte("\"\""), false},
		{"whitespace_only", []byte("   "), false},
		{"object_with_whitespace", []byte("{   }"), true},
		{"array_with_whitespace", []byte("[   ]"), true},
		{"string_with_whitespace", []byte("   \"text\""), false},
		{"number", []byte("123"), false},
		{"boolean_true", []byte("true"), false},
		{"boolean_false", []byte("false"), false},
		{"null_value", []byte("null"), false}, {"invalid JSON", []byte("invalid"), false},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			require_Equal(t, isJSONObjectOrArray(test.data), test.valid)
		})
	}
}

func TestJetStreamSourcingClipStartSeq(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "ORIGIN",
		Subjects: []string{"test"},
	})
	require_NoError(t, err)

	for i := 0; i < 10; i++ {
		_, err := js.Publish("test", nil)
		require_NoError(t, err)
	}

	_, err = js.AddStream(&nats.StreamConfig{
		Name: "SOURCING",
		Sources: []*nats.StreamSource{
			{
				Name:        "ORIGIN",
				OptStartSeq: 20,
			},
		},
	})
	require_NoError(t, err)

	// Wait for sourcing consumer to be created.
	time.Sleep(time.Second)

	mset, err := s.GlobalAccount().lookupStream("ORIGIN")
	require_NoError(t, err)
	require_True(t, mset != nil)
	require_Len(t, len(mset.consumers), 1)
	for _, o := range mset.consumers {
		// Should have been clipped back to below 20 as only
		// 10 messages in the origin stream.
		require_Equal(t, o.sseq, 11)
	}
}

func TestJetStreamMirroringClipStartSeq(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "ORIGIN",
		Subjects: []string{"test"},
	})
	require_NoError(t, err)

	for i := 0; i < 10; i++ {
		_, err := js.Publish("test", nil)
		require_NoError(t, err)
	}

	_, err = js.AddStream(&nats.StreamConfig{
		Name: "MIRRORING",
		Mirror: &nats.StreamSource{
			Name:        "ORIGIN",
			OptStartSeq: 20,
		},
	})
	require_NoError(t, err)

	// Wait for mirroring consumer to be created.
	time.Sleep(time.Second)

	mset, err := s.GlobalAccount().lookupStream("ORIGIN")
	require_NoError(t, err)
	require_True(t, mset != nil)
	require_Len(t, len(mset.consumers), 1)
	for _, o := range mset.consumers {
		// Should have been clipped back to below 20 as only
		// 10 messages in the origin stream.
		require_Equal(t, o.sseq, 11)
	}
}

func TestJetStreamDelayedAPIResponses(t *testing.T) {
	tdir := t.TempDir()
	tmpl := `
		listen: 127.0.0.1:-1
		%sjetstream: {max_mem_store: 64GB, max_file_store: 10TB, store_dir: %q}
	`
	conf := createConfFile(t, []byte(fmt.Sprintf(tmpl, "", tdir)))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	nc := natsConnect(t, s.ClientURL())
	defer nc.Close()

	sub := natsSubSync(t, nc, JSAuditAdvisory)

	acc := s.GlobalAccount()

	// Send B, A, D, C and expected to receive A, B, C, D
	s.sendDelayedAPIErrResponse(nil, acc, "B", _EMPTY_, "request2", "response2", nil, 500*time.Millisecond)
	time.Sleep(50 * time.Millisecond)
	s.sendDelayedAPIErrResponse(nil, acc, "A", _EMPTY_, "request1", "response1", nil, 200*time.Millisecond)
	time.Sleep(50 * time.Millisecond)
	s.sendDelayedAPIErrResponse(nil, acc, "D", _EMPTY_, "request4", "response4", nil, 800*time.Millisecond)
	time.Sleep(50 * time.Millisecond)
	s.sendDelayedAPIErrResponse(nil, acc, "C", _EMPTY_, "request3", "response3", nil, 650*time.Millisecond)

	check := func(req, resp string) {
		t.Helper()
		msg := natsNexMsg(t, sub, time.Second)
		var audit JSAPIAudit
		err := json.Unmarshal(msg.Data, &audit)
		require_NoError(t, err)
		require_Equal(t, audit.Request, req)
		require_Equal(t, audit.Response, resp)
	}
	check("request1", "response1")
	check("request2", "response2")
	check("request3", "response3")
	check("request4", "response4")

	// Verify that if a raft group is canceled, the delayed API response is canceled too.
	node := &raft{quit: make(chan struct{})}
	g := &raftGroup{node: node}
	// Send delayed API response with this raft group
	s.sendDelayedAPIErrResponse(nil, acc, "E", _EMPTY_, "request5", "response5", g, 250*time.Millisecond)
	time.Sleep(50 * time.Millisecond)
	// Send that one without a group
	s.sendDelayedAPIErrResponse(nil, acc, "F", _EMPTY_, "request6", "response6", nil, 400*time.Millisecond)
	// Close the "request5"'s channel.
	close(node.quit)
	// So we should receive request6, not 5.
	check("request6", "response6")

	// Check config reload.
	s.sendDelayedAPIErrResponse(nil, acc, "G", _EMPTY_, "request7", "response7", nil, 400*time.Millisecond)
	time.Sleep(50 * time.Millisecond)
	// Send a bunch more
	for i := 0; i < 10; i++ {
		s.sendDelayedAPIErrResponse(nil, acc, "H", _EMPTY_, "request8", "response8", nil, 500*time.Millisecond)
	}
	// Config reload to disable JS.
	reloadUpdateConfig(t, s, conf, fmt.Sprintf(tmpl, "#", tdir))
	check("request7", "response7")
	// We should not receive more.
	if msg, err := sub.NextMsg(600 * time.Millisecond); err != nats.ErrTimeout {
		t.Fatalf("Did not expect to receive: %s", msg.Data)
	}
	// Check that the queue is empty.
	s.mu.RLock()
	q := s.delayedAPIResponses
	s.mu.RUnlock()
	require_Equal(t, q.len(), 0)

	// Restore JS and check delayed response can be received.
	reloadUpdateConfig(t, s, conf, fmt.Sprintf(tmpl, "", tdir))
	// Wait until js is re-enabled
	checkFor(t, 10*time.Second, 50*time.Millisecond, func() error {
		if s.getJetStream() == nil {
			return ErrJetStreamNotEnabled
		}
		return nil
	})
	s.sendDelayedAPIErrResponse(nil, acc, "I", _EMPTY_, "request9", "response9", nil, 100*time.Millisecond)
	check("request9", "response9")
}

func TestJetStreamMemoryPurgeClearsSubjectsState(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"foo"},
		Storage:  nats.MemoryStorage,
	})
	require_NoError(t, err)

	pa, err := js.Publish("foo", nil)
	require_NoError(t, err)
	require_Equal(t, pa.Sequence, 1)

	// When requesting stream info, we expect one subject foo with one entry.
	si, err := js.StreamInfo("TEST", &nats.StreamInfoRequest{SubjectsFilter: ">"})
	require_NoError(t, err)
	require_Len(t, len(si.State.Subjects), 1)
	require_Equal(t, si.State.Subjects["foo"], 1)

	// After purging, moving the sequence up, the subjects state should be cleared.
	err = js.PurgeStream("TEST", &nats.StreamPurgeRequest{Sequence: 100})
	require_NoError(t, err)

	si, err = js.StreamInfo("TEST", &nats.StreamInfoRequest{SubjectsFilter: ">"})
	require_NoError(t, err)
	require_Len(t, len(si.State.Subjects), 0)
}

func TestJetStreamWouldExceedLimits(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	js := s.getJetStream()
	require_NotNil(t, js)

	// Storing exactly up to the limit should work.
	require_False(t, js.wouldExceedLimits(MemoryStorage, int(js.config.MaxMemory)))
	require_False(t, js.wouldExceedLimits(FileStorage, int(js.config.MaxStore)))

	// Storing one more than the max should exceed limits.
	require_True(t, js.wouldExceedLimits(MemoryStorage, int(js.config.MaxMemory)+1))
	require_True(t, js.wouldExceedLimits(FileStorage, int(js.config.MaxStore)+1))
}

func TestJetStreamMessageTTL(t *testing.T) {
	for _, storage := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			jsStreamCreate(t, nc, &StreamConfig{
				Name:        "TEST",
				Storage:     storage,
				Subjects:    []string{"test"},
				AllowMsgTTL: true,
			})

			msg := &nats.Msg{
				Subject: "test",
				Header:  nats.Header{},
			}

			for i := 1; i <= 10; i++ {
				msg.Header.Set(JSMessageTTL, "1s")
				_, err := js.PublishMsg(msg)
				require_NoError(t, err)
			}

			si, err := js.StreamInfo("TEST")
			require_NoError(t, err)
			require_Equal(t, si.State.Msgs, 10)
			require_Equal(t, si.State.FirstSeq, 1)
			require_Equal(t, si.State.LastSeq, 10)

			time.Sleep(time.Second * 2)

			si, err = js.StreamInfo("TEST")
			require_NoError(t, err)
			require_Equal(t, si.State.Msgs, 0)
			require_Equal(t, si.State.FirstSeq, 11)
			require_Equal(t, si.State.LastSeq, 10)
		})
	}
}

func TestJetStreamMessageTTLRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	jsStreamCreate(t, nc, &StreamConfig{
		Name:        "TEST",
		Storage:     FileStorage,
		Subjects:    []string{"test"},
		AllowMsgTTL: true,
	})

	msg := &nats.Msg{
		Subject: "test",
		Header:  nats.Header{},
	}

	for i := 1; i <= 10; i++ {
		msg.Header.Set(JSMessageTTL, "1s")
		_, err := js.PublishMsg(msg)
		require_NoError(t, err)
	}

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 10)
	require_Equal(t, si.State.FirstSeq, 1)
	require_Equal(t, si.State.LastSeq, 10)

	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()

	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 10)
	require_Equal(t, si.State.FirstSeq, 1)
	require_Equal(t, si.State.LastSeq, 10)

	time.Sleep(time.Second * 2)

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 0)
	require_Equal(t, si.State.FirstSeq, 11)
	require_Equal(t, si.State.LastSeq, 10)
}

func TestJetStreamMessageTTLRecovered(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	jsStreamCreate(t, nc, &StreamConfig{
		Name:        "TEST",
		Storage:     FileStorage,
		Subjects:    []string{"test"},
		AllowMsgTTL: true,
	})

	msg := &nats.Msg{
		Subject: "test",
		Header:  nats.Header{},
	}

	for i := 1; i <= 10; i++ {
		msg.Header.Set(JSMessageTTL, "1s")
		_, err := js.PublishMsg(msg)
		require_NoError(t, err)
	}

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 10)
	require_Equal(t, si.State.FirstSeq, 1)
	require_Equal(t, si.State.LastSeq, 10)

	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()

	fn := filepath.Join(sd, globalAccountName, streamsDir, "TEST", msgDir, ttlStreamStateFile)
	require_NoError(t, os.RemoveAll(fn))

	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 10)
	require_Equal(t, si.State.FirstSeq, 1)
	require_Equal(t, si.State.LastSeq, 10)

	time.Sleep(time.Second * 2)

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 0)
	require_Equal(t, si.State.FirstSeq, 11)
	require_Equal(t, si.State.LastSeq, 10)
}

func TestJetStreamMessageTTLInvalid(t *testing.T) {
	for _, storage := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			jsStreamCreate(t, nc, &StreamConfig{
				Name:        "TEST",
				Storage:     storage,
				Subjects:    []string{"test"},
				AllowMsgTTL: true,
			})

			msg := &nats.Msg{
				Subject: "test",
				Header:  nats.Header{},
			}

			msg.Header.Set(JSMessageTTL, "500ms")
			_, err := js.PublishMsg(msg)
			require_Error(t, err)

			msg.Header.Set(JSMessageTTL, "something")
			_, err = js.PublishMsg(msg)
			require_Error(t, err)
		})
	}
}

func TestJetStreamMessageTTLNotUpdatable(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, _ := jsClientConnect(t, s)
	defer nc.Close()

	jsStreamCreate(t, nc, &StreamConfig{
		Name:        "TEST",
		Storage:     FileStorage,
		Subjects:    []string{"test"},
		AllowMsgTTL: true,
	})

	_, err := jsStreamUpdate(t, nc, &StreamConfig{
		Name:        "TEST",
		Storage:     FileStorage,
		Subjects:    []string{"test"},
		AllowMsgTTL: false,
	})
	require_Error(t, err)
}

func TestJetStreamMessageTTLNeverExpire(t *testing.T) {
	for _, storage := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			jsStreamCreate(t, nc, &StreamConfig{
				Name:        "TEST",
				Storage:     storage,
				Subjects:    []string{"test"},
				AllowMsgTTL: true,
				MaxAge:      time.Second,
			})

			msg := &nats.Msg{
				Subject: "test",
				Header:  nats.Header{},
			}

			// The first message we publish is set to "never expire", therefore it
			// won't age out with the MaxAge policy.
			msg.Header.Set(JSMessageTTL, "never")
			_, err := js.PublishMsg(msg)
			require_NoError(t, err)

			// Following messages will be published as normal and will age out.
			msg.Header.Del(JSMessageTTL)
			for i := 1; i <= 10; i++ {
				_, err := js.PublishMsg(msg)
				require_NoError(t, err)
			}

			si, err := js.StreamInfo("TEST")
			require_NoError(t, err)
			require_Equal(t, si.State.Msgs, 11)
			require_Equal(t, si.State.FirstSeq, 1)
			require_Equal(t, si.State.LastSeq, 11)

			time.Sleep(time.Second * 2)

			si, err = js.StreamInfo("TEST")
			require_NoError(t, err)
			require_Equal(t, si.State.Msgs, 1)
			require_Equal(t, si.State.FirstSeq, 1)
			require_Equal(t, si.State.LastSeq, 11)
		})
	}
}

func TestJetStreamMessageTTLDisabled(t *testing.T) {
	for _, storage := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			jsStreamCreate(t, nc, &StreamConfig{
				Name:     "TEST",
				Storage:  storage,
				Subjects: []string{"test"},
			})

			msg := &nats.Msg{
				Subject: "test",
				Header:  nats.Header{},
			}

			msg.Header.Set(JSMessageTTL, "1s")
			_, err := js.PublishMsg(msg)
			require_Error(t, err)
		})
	}
}

func TestJetStreamMessageTTLWhenSourcing(t *testing.T) {
	for _, storage := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := jsStreamCreate(t, nc, &StreamConfig{
				Name:        "Origin",
				Storage:     storage,
				Subjects:    []string{"test"},
				AllowMsgTTL: true,
			})
			require_NoError(t, err)

			_, err = jsStreamCreate(t, nc, &StreamConfig{
				Name:    "TTLEnabled",
				Storage: storage,
				Sources: []*StreamSource{
					{Name: "Origin"},
				},
				AllowMsgTTL: true,
			})
			require_NoError(t, err)

			ttlDisabledConfig := &StreamConfig{
				Name:    "TTLDisabled",
				Storage: storage,
				Sources: []*StreamSource{
					{Name: "Origin"},
				},
				AllowMsgTTL: false,
			}
			_, err = jsStreamCreate(t, nc, ttlDisabledConfig)
			require_NoError(t, err)

			hdr := nats.Header{}
			hdr.Add(JSMessageTTL, "1s")

			_, err = js.PublishMsg(&nats.Msg{
				Subject: "test",
				Header:  hdr,
			})
			require_NoError(t, err)

			for _, stream := range []string{"TTLEnabled", "TTLDisabled"} {
				t.Run(stream, func(t *testing.T) {
					sc, err := js.PullSubscribe("test", "consumer", nats.BindStream(stream))
					require_NoError(t, err)

					msgs, err := sc.Fetch(1)
					require_NoError(t, err)
					require_Len(t, len(msgs), 1)
					require_Equal(t, msgs[0].Header.Get(JSMessageTTL), "1s")

					time.Sleep(time.Second)

					si, err := js.StreamInfo(stream)
					require_NoError(t, err)

					if stream != "TTLDisabled" {
						require_Equal(t, si.State.Msgs, 0)
						return
					}

					require_Equal(t, si.State.Msgs, 1)

					ttlDisabledConfig.AllowMsgTTL = true
					_, err = jsStreamUpdate(t, nc, ttlDisabledConfig)
					require_NoError(t, err)

					si, err = js.StreamInfo(stream)
					require_NoError(t, err)
					require_Equal(t, si.State.Msgs, 0)
				})
			}
		})
	}
}

func TestJetStreamMessageTTLWhenMirroring(t *testing.T) {
	for _, storage := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := jsStreamCreate(t, nc, &StreamConfig{
				Name:        "Origin",
				Storage:     storage,
				Subjects:    []string{"test"},
				AllowMsgTTL: true,
			})
			require_NoError(t, err)

			_, err = jsStreamCreate(t, nc, &StreamConfig{
				Name:    "TTLEnabled",
				Storage: storage,
				Mirror: &StreamSource{
					Name: "Origin",
				},
				AllowMsgTTL: true,
			})
			require_NoError(t, err)

			ttlDisabledConfig := &StreamConfig{
				Name:    "TTLDisabled",
				Storage: storage,
				Mirror: &StreamSource{
					Name: "Origin",
				},
				AllowMsgTTL: false,
			}
			_, err = jsStreamCreate(t, nc, ttlDisabledConfig)
			require_NoError(t, err)

			hdr := nats.Header{}
			hdr.Add(JSMessageTTL, "1s")

			_, err = js.PublishMsg(&nats.Msg{
				Subject: "test",
				Header:  hdr,
			})
			require_NoError(t, err)

			for _, stream := range []string{"TTLEnabled", "TTLDisabled"} {
				t.Run(stream, func(t *testing.T) {
					sc, err := js.PullSubscribe("test", "consumer", nats.BindStream(stream))
					require_NoError(t, err)

					msgs, err := sc.Fetch(1)
					require_NoError(t, err)
					require_Len(t, len(msgs), 1)
					require_Equal(t, msgs[0].Header.Get(JSMessageTTL), "1s")

					time.Sleep(time.Second)

					si, err := js.StreamInfo(stream)
					require_NoError(t, err)
					if stream != "TTLDisabled" {
						require_Equal(t, si.State.Msgs, 0)
						return
					}

					require_Equal(t, si.State.Msgs, 1)

					ttlDisabledConfig.AllowMsgTTL = true
					_, err = jsStreamUpdate(t, nc, ttlDisabledConfig)
					require_NoError(t, err)

					si, err = js.StreamInfo(stream)
					require_NoError(t, err)
					require_Equal(t, si.State.Msgs, 0)
				})
			}
		})
	}
}

func TestJetStreamSubjectDeleteMarkers(t *testing.T) {
	for _, storage := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			jsStreamCreate(t, nc, &StreamConfig{
				Name:                   "TEST",
				Storage:                storage,
				Subjects:               []string{"test"},
				MaxAge:                 time.Second,
				AllowMsgTTL:            true,
				SubjectDeleteMarkerTTL: time.Second,
			})

			sub, err := js.SubscribeSync("test")
			require_NoError(t, err)

			for i := 0; i < 3; i++ {
				_, err = js.Publish("test", nil)
				require_NoError(t, err)
			}

			for i := 0; i < 3; i++ {
				msg, err := sub.NextMsg(time.Second)
				require_NoError(t, err)
				require_NoError(t, msg.AckSync())
			}

			msg, err := sub.NextMsg(time.Second * 10)
			require_NoError(t, err)
			require_Equal(t, msg.Header.Get(JSMarkerReason), "MaxAge")
			require_Equal(t, msg.Header.Get(JSMessageTTL), "1s")
		})
	}
}

func TestJetStreamSubjectDeleteMarkersAfterRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := jsStreamCreate(t, nc, &StreamConfig{
		Name:                   "TEST",
		Storage:                FileStorage,
		Subjects:               []string{"test"},
		MaxAge:                 time.Second,
		AllowMsgTTL:            true,
		SubjectDeleteMarkerTTL: time.Second,
	})
	require_NoError(t, err)

	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{
		Name:      "test_consumer",
		AckPolicy: nats.AckExplicitPolicy,
	})
	require_NoError(t, err)

	for i := 0; i < 3; i++ {
		_, err = js.Publish("test", nil)
		require_NoError(t, err)
	}

	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()

	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()

	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	sub, err := js.PullSubscribe("test", _EMPTY_, nats.Bind("TEST", "test_consumer"))
	require_NoError(t, err)

	for i := 0; i < 3; i++ {
		msgs, err := sub.Fetch(1)
		require_NoError(t, err)
		require_Len(t, len(msgs), 1)
		require_NoError(t, msgs[0].AckSync())
	}

	msgs, err := sub.Fetch(1)
	require_NoError(t, err)
	require_Len(t, len(msgs), 1)
	require_Equal(t, msgs[0].Header.Get(JSMarkerReason), "MaxAge")
	require_Equal(t, msgs[0].Header.Get(JSMessageTTL), "1s")
}

func TestJetStreamSubjectDeleteMarkersTTLRollupWithMaxAge(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	jsStreamCreate(t, nc, &StreamConfig{
		Name:                   "TEST",
		Storage:                FileStorage,
		Subjects:               []string{"test"},
		MaxAge:                 time.Second,
		AllowMsgTTL:            true,
		AllowRollup:            true,
		SubjectDeleteMarkerTTL: time.Second,
	})

	sub, err := js.SubscribeSync("test")
	require_NoError(t, err)

	for i := 0; i < 3; i++ {
		_, err = js.Publish("test", nil)
		require_NoError(t, err)
	}

	for i := 0; i < 3; i++ {
		msg, err := sub.NextMsg(time.Second)
		require_NoError(t, err)
		require_NoError(t, msg.AckSync())
	}

	rh := nats.Header{}
	rh.Set(JSMessageTTL, "2s") // MaxAge will get here first.
	rh.Set(JSMsgRollup, JSMsgRollupSubject)
	_, err = js.PublishMsg(&nats.Msg{
		Subject: "test",
		Header:  rh,
	})
	require_NoError(t, err)

	// Expect to only have the rollup message here.
	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 1)
	require_Equal(t, si.State.FirstSeq, 4)

	msg, err := sub.NextMsg(time.Second * 10)
	require_NoError(t, err)
	require_Equal(t, msg.Header.Get(JSMsgRollup), JSMsgRollupSubject)
	require_Equal(t, msg.Header.Get(JSMessageTTL), "2s")
	meta, err := msg.Metadata()
	require_NoError(t, err)
	require_NoError(t, msg.AckSync())

	msg, err = sub.NextMsg(time.Second * 10)
	require_NoError(t, err)
	require_LessThan(t, time.Second, time.Since(meta.Timestamp))
	require_Equal(t, msg.Header.Get(JSMarkerReason), "MaxAge")
	require_Equal(t, msg.Header.Get(JSMessageTTL), "1s")
}

func TestJetStreamSubjectDeleteMarkersTTLRollupWithoutMaxAge(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := jsStreamCreate(t, nc, &StreamConfig{
		Name:                   "TEST",
		Storage:                FileStorage,
		Subjects:               []string{"test"},
		AllowMsgTTL:            true,
		AllowRollup:            true,
		SubjectDeleteMarkerTTL: time.Second,
	})
	require_NoError(t, err)

	sub, err := js.SubscribeSync("test")
	require_NoError(t, err)

	for i := 0; i < 3; i++ {
		_, err = js.Publish("test", nil)
		require_NoError(t, err)
	}

	for i := 0; i < 3; i++ {
		msg, err := sub.NextMsg(time.Second)
		require_NoError(t, err)
		require_NoError(t, msg.AckSync())
	}

	rh := nats.Header{}
	rh.Set(JSMessageTTL, "1s")
	rh.Set(JSMsgRollup, JSMsgRollupSubject)
	_, err = js.PublishMsg(&nats.Msg{
		Subject: "test",
		Header:  rh,
	})
	require_NoError(t, err)

	// Expect to only have the rollup message here.
	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 1)
	require_Equal(t, si.State.FirstSeq, 4)

	msg, err := sub.NextMsg(time.Second * 10)
	require_NoError(t, err)
	require_Equal(t, msg.Header.Get(JSMsgRollup), JSMsgRollupSubject)
	require_Equal(t, msg.Header.Get(JSMessageTTL), "1s")
	require_NoError(t, msg.AckSync())

	// Wait for the rollup message to hit the TTL.
	time.Sleep(2500 * time.Millisecond)

	// Now it should be gone, and it will have been replaced with a
	// subject delete marker (which is also gone by now).
	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 0)
	require_Equal(t, si.State.FirstSeq, 6)
}

func TestJetStreamSubjectDeleteMarkersWithMirror(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, _ := jsClientConnect(t, s)
	defer nc.Close()

	_, err := jsStreamCreate(t, nc, &StreamConfig{
		Name:     "Origin",
		Storage:  FileStorage,
		Subjects: []string{"test"},
		MaxAge:   time.Second,
	})
	require_NoError(t, err)

	_, err = jsStreamCreate(t, nc, &StreamConfig{
		Name:                   "Mirror",
		Storage:                FileStorage,
		AllowMsgTTL:            true,
		SubjectDeleteMarkerTTL: time.Second,
		Mirror: &StreamSource{
			Name: "Origin",
		},
	})
	require_Error(t, err)
}

// https://github.com/nats-io/nats-server/issues/6538
func TestJetStreamInterestMaxDeliveryReached(t *testing.T) {
	maxWait := 250 * time.Millisecond
	for _, useNak := range []bool{true, false} {
		for _, test := range []struct {
			title  string
			action func(s *Server, sub *nats.Subscription)
		}{
			{
				title: "fetch",
				action: func(s *Server, sub *nats.Subscription) {
					time.Sleep(time.Second)

					// max deliver 1 so this will fail
					_, err := sub.Fetch(1, nats.MaxWait(maxWait))
					require_Error(t, err)
				},
			},
			{
				title: "expire pending",
				action: func(s *Server, sub *nats.Subscription) {
					acc, err := s.lookupAccount(globalAccountName)
					require_NoError(t, err)
					mset, err := acc.lookupStream("TEST")
					require_NoError(t, err)
					o := mset.lookupConsumer("consumer")
					require_NotNil(t, o)

					o.mu.Lock()
					o.forceExpirePending()
					o.mu.Unlock()
				},
			},
		} {
			title := fmt.Sprintf("nak/%s", test.title)
			if !useNak {
				title = fmt.Sprintf("no-%s", title)
			}
			t.Run(title, func(t *testing.T) {
				s := RunBasicJetStreamServer(t)
				defer s.Shutdown()

				nc, js := jsClientConnect(t, s)
				defer nc.Close()

				_, err := js.AddStream(&nats.StreamConfig{
					Name:      "TEST",
					Storage:   nats.FileStorage,
					Subjects:  []string{"test"},
					Replicas:  1,
					Retention: nats.InterestPolicy,
				})
				require_NoError(t, err)

				sub, err := js.PullSubscribe("test", "consumer", nats.AckWait(time.Second), nats.MaxDeliver(1))
				require_NoError(t, err)

				_, err = nc.Request("test", []byte("hello"), maxWait)
				require_NoError(t, err)

				nfo, err := js.StreamInfo("TEST")
				require_NoError(t, err)
				require_Equal(t, nfo.State.Msgs, uint64(1))

				msg, err := sub.Fetch(1, nats.MaxWait(maxWait))
				require_NoError(t, err)
				require_Len(t, 1, len(msg))
				if useNak {
					require_NoError(t, msg[0].Nak())
				}

				cnfo, err := js.ConsumerInfo("TEST", "consumer")
				require_NoError(t, err)
				require_Equal(t, cnfo.NumAckPending, 1)

				test.action(s, sub)

				// max deliver 1 so this will fail
				_, err = sub.Fetch(1, nats.MaxWait(maxWait))
				require_Error(t, err)

				cnfo, err = js.ConsumerInfo("TEST", "consumer")
				require_NoError(t, err)
				require_Equal(t, cnfo.NumAckPending, 0)

				nfo, err = js.StreamInfo("TEST")
				require_NoError(t, err)
				require_Equal(t, nfo.State.Msgs, uint64(1))

				sub2, err := js.PullSubscribe("test", "consumer2")
				require_NoError(t, err)

				msg, err = sub2.Fetch(1)
				require_NoError(t, err)
				require_Len(t, 1, len(msg))
				require_NoError(t, msg[0].AckSync())

				nfo, err = js.StreamInfo("TEST")
				require_NoError(t, err)
				require_Equal(t, nfo.State.Msgs, uint64(1))
			})
		}
	}
}

// https://github.com/nats-io/nats-server/issues/6874
func TestJetStreamMaxDeliveryRedeliveredReporting(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "TEST",
		Storage:   nats.FileStorage,
		Subjects:  []string{"foo"},
		Replicas:  1,
		Retention: nats.LimitsPolicy,
	})
	require_NoError(t, err)

	_, err = js.Publish("foo", nil)
	require_NoError(t, err)

	maxWait := 250 * time.Millisecond
	cfg := &nats.ConsumerConfig{
		Durable:    "CONSUMER",
		AckPolicy:  nats.AckExplicitPolicy,
		AckWait:    maxWait,
		MaxDeliver: 1,
	}
	_, err = js.AddConsumer("TEST", cfg)
	require_NoError(t, err)

	sub, err := js.PullSubscribe(_EMPTY_, "CONSUMER", nats.BindStream("TEST"))
	require_NoError(t, err)

	nfo, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, nfo.State.Msgs, uint64(1))

	msgs, err := sub.Fetch(1, nats.MaxWait(maxWait))
	require_NoError(t, err)
	require_Len(t, 1, len(msgs))

	cnfo, err := js.ConsumerInfo("TEST", "CONSUMER")
	require_NoError(t, err)
	require_Equal(t, cnfo.NumAckPending, 1)
	require_Equal(t, cnfo.NumRedelivered, 0)

	time.Sleep(2 * maxWait)

	// Max deliver 1 so this will fail.
	_, err = sub.Fetch(1, nats.MaxWait(maxWait))
	require_Error(t, err)

	// Redelivered should remain 0, as it doesn't get redelivered with MaxDeliver 1.
	cnfo, err = js.ConsumerInfo("TEST", "CONSUMER")
	require_NoError(t, err)
	require_Equal(t, cnfo.NumAckPending, 0)
	require_Equal(t, cnfo.NumRedelivered, 0)

	// With a higher MaxDeliver we should report it.
	cfg.MaxDeliver = 2
	_, err = js.UpdateConsumer("TEST", cfg)
	require_NoError(t, err)

	cnfo, err = js.ConsumerInfo("TEST", "CONSUMER")
	require_NoError(t, err)
	require_Equal(t, cnfo.NumAckPending, 0)
	require_Equal(t, cnfo.NumRedelivered, 1)

	// Unset should also report.
	cfg.MaxDeliver = -1
	_, err = js.UpdateConsumer("TEST", cfg)
	require_NoError(t, err)

	cnfo, err = js.ConsumerInfo("TEST", "CONSUMER")
	require_NoError(t, err)
	require_Equal(t, cnfo.NumAckPending, 0)
	require_Equal(t, cnfo.NumRedelivered, 1)
}

func TestJetStreamRecoversStreamFirstSeqWhenNotEmpty(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "TEST",
		Storage:   nats.FileStorage,
		Subjects:  []string{"test"},
		Retention: nats.InterestPolicy,
	})
	require_NoError(t, err)

	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{
		Name:          "CONSUMER",
		FilterSubject: "test",
		AckPolicy:     nats.AckExplicitPolicy,
	})
	require_NoError(t, err)

	for i := 0; i < 1000; i++ {
		_, err = js.Publish("test", nil)
		require_NoError(t, err)
	}

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 1000)
	require_Equal(t, si.State.FirstSeq, 1)
	require_Equal(t, si.State.LastSeq, 1000)

	ps, err := js.PullSubscribe("test", "", nats.Bind("TEST", "CONSUMER"))
	require_NoError(t, err)

	for i := 0; i < 500; i++ {
		msgs, err := ps.Fetch(1)
		require_NoError(t, err)
		require_Len(t, len(msgs), 1)
		require_NoError(t, msgs[0].AckSync())
	}

	ci, err := js.ConsumerInfo("TEST", "CONSUMER")
	require_NoError(t, err)
	require_Equal(t, ci.AckFloor.Stream, 500)

	s.shutdownJetStream()

	path := filepath.Join(s.opts.StoreDir, "jetstream", globalAccountName, "streams", "TEST", msgDir)
	dir, err := os.ReadDir(path)
	require_NoError(t, err)

	// Mangle the last message in the block so that it fails the checksum comparison
	// with index.db, which causes us to throw the prior state error and rebuild.
	// Once this is done we should still be able to figure out what the previous first
	// and last sequence were, even without messages.
	for _, f := range dir {
		if !strings.HasSuffix(f.Name(), ".blk") {
			continue
		}
		st, err := f.Info()
		require_NoError(t, err)
		require_NoError(t, os.Truncate(filepath.Join(path, f.Name()), st.Size()-1))
	}

	s.restartJetStream()

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 500)
	require_Equal(t, si.State.FirstSeq, 501)
	require_Equal(t, si.State.LastSeq, 1000)
}

func TestJetStreamRecoversStreamFirstSeqWhenEmpty(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "TEST",
		Storage:   nats.FileStorage,
		Subjects:  []string{"test"},
		Retention: nats.InterestPolicy,
	})
	require_NoError(t, err)

	_, err = js.AddConsumer("TEST", &nats.ConsumerConfig{Durable: "CONSUMER"})
	require_NoError(t, err)

	for i := 0; i < 1000; i++ {
		_, err = js.Publish("test", nil)
		require_NoError(t, err)
	}

	require_NoError(t, js.PurgeStream("TEST"))

	si, err := js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 0)
	require_Equal(t, si.State.FirstSeq, 1001)
	require_Equal(t, si.State.LastSeq, 1000)

	ci, err := js.ConsumerInfo("TEST", "CONSUMER")
	require_NoError(t, err)
	require_Equal(t, ci.AckFloor.Stream, 1000)

	s.shutdownJetStream()

	path := filepath.Join(s.opts.StoreDir, "jetstream", globalAccountName, "streams", "TEST", msgDir)
	dir, err := os.ReadDir(path)
	require_NoError(t, err)

	// Mangle the last message in the block so that it fails the checksum comparison
	// with index.db, which causes us to throw the prior state error and rebuild.
	// Once this is done we should still be able to figure out what the previous first
	// and last sequence were, even without messages.
	for _, f := range dir {
		if !strings.HasSuffix(f.Name(), ".blk") {
			continue
		}
		st, err := f.Info()
		require_NoError(t, err)
		require_NoError(t, os.Truncate(filepath.Join(path, f.Name()), st.Size()-1))
	}

	s.restartJetStream()

	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 0)
	require_Equal(t, si.State.FirstSeq, 1001)
	require_Equal(t, si.State.LastSeq, 1000)
}

func TestJetStreamUpgradeStreamVersioning(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	acc, err := s.lookupAccount(globalAccountName)
	require_NoError(t, err)

	// Create stream config.
	cfg, apiErr := s.checkStreamCfg(&StreamConfig{Name: "TEST", Subjects: []string{"foo"}}, acc, false)
	require_True(t, apiErr == nil)

	// Create stream.
	mset, err := acc.addStream(&cfg)
	require_NoError(t, err)
	require_True(t, mset.cfg.Metadata == nil)

	for _, create := range []bool{true, false} {
		title := "create"
		if !create {
			title = "update"
		}
		t.Run(title, func(t *testing.T) {
			if create {
				// Create on 2.11+ should be idempotent with previous create on 2.10-.
				mcfg := &StreamConfig{}
				setStaticStreamMetadata(mcfg)
				si, err := js.AddStream(&nats.StreamConfig{
					Name:     "TEST",
					Subjects: []string{"foo"},
					Metadata: setDynamicStreamMetadata(mcfg).Metadata,
				})
				require_NoError(t, err)
				deleteDynamicMetadata(si.Config.Metadata)
				require_Len(t, len(si.Config.Metadata), 0)
			} else {
				// Update populates the versioning metadata.
				si, err := js.UpdateStream(&nats.StreamConfig{Name: "TEST", Subjects: []string{"foo"}})
				require_NoError(t, err)
				require_Len(t, len(si.Config.Metadata), 3)
			}
		})
	}
}

func TestJetStreamUpgradeConsumerVersioning(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:      "TEST",
		Subjects:  []string{"foo"},
		Retention: nats.LimitsPolicy,
		Replicas:  1,
	})
	require_NoError(t, err)

	acc, err := s.lookupAccount(globalAccountName)
	require_NoError(t, err)
	mset, err := acc.lookupStream("TEST")
	require_NoError(t, err)

	// Create consumer config.
	cfg := &ConsumerConfig{Durable: "CONSUMER"}
	selectedLimits, _, _, apiErr := acc.selectLimits(cfg.replicas(&mset.cfg))
	if apiErr != nil {
		require_NoError(t, apiErr)
	}
	srvLim := &s.getOpts().JetStreamLimits
	apiErr = setConsumerConfigDefaults(cfg, &mset.cfg, srvLim, selectedLimits, false)
	if apiErr != nil {
		require_NoError(t, apiErr)
	}

	// Create consumer.
	_, err = mset.addConsumer(cfg)
	require_NoError(t, err)

	for _, create := range []bool{true, false} {
		title := "create"
		if !create {
			title = "update"
		}
		t.Run(title, func(t *testing.T) {
			createConsumerRequest := func(obsReq CreateConsumerRequest) (*JSApiConsumerInfoResponse, error) {
				req, err := json.Marshal(obsReq)
				if err != nil {
					return nil, err
				}
				msg, err := nc.Request(fmt.Sprintf(JSApiDurableCreateT, "TEST", "CONSUMER"), req, time.Second)
				if err != nil {
					return nil, err
				}
				var resp JSApiConsumerInfoResponse
				require_NoError(t, json.Unmarshal(msg.Data, &resp))
				if resp.Error != nil {
					return nil, resp.Error
				}
				return &resp, nil
			}

			if create {
				// Create on 2.11+ should be idempotent with previous create on 2.10-.
				ncfg := &ConsumerConfig{Durable: "CONSUMER"}
				setStaticConsumerMetadata(ncfg)
				obsReq := CreateConsumerRequest{
					Stream: "TEST",
					Config: *setDynamicConsumerMetadata(ncfg),
					Action: ActionCreate,
				}
				resp, err := createConsumerRequest(obsReq)
				require_NoError(t, err)
				deleteDynamicMetadata(resp.Config.Metadata)
				require_Len(t, len(resp.Config.Metadata), 0)
			} else {
				// Update populates the versioning metadata.
				obsReq := CreateConsumerRequest{
					Stream: "TEST",
					Config: ConsumerConfig{Durable: "CONSUMER"},
					Action: ActionUpdate,
				}
				resp, err := createConsumerRequest(obsReq)
				require_NoError(t, err)
				require_Len(t, len(resp.Config.Metadata), 3)
			}
		})
	}
}

func TestJetStreamMirrorCrossAccountWithFilteredSubjectAndSubjectTransform(t *testing.T) {
	conf := createConfFile(t, fmt.Appendf(nil, `
		listen: "127.0.0.1:-1"
		jetstream: {store_dir: %q}
		accounts: {
			PUBLIC_ACCOUNT: {
				jetstream: enabled
				exports: [
					{ service: "$JS.API.CONSUMER.CREATE.S.*.public.a", response_type: stream, accounts: ["INTERNAL_ACCOUNT"] },
					{ service: "$JS.API.CONSUMER.CREATE.S.*.public.b", response_type: stream, accounts: ["INTERNAL_ACCOUNT"] },
					{ service: "$JS.API.CONSUMER.CREATE.S.*.public.c", response_type: stream, accounts: ["INTERNAL_ACCOUNT"] },
					{ service: "$JS.FC.>" },
					{ stream: "shared.public.>", accounts: ["INTERNAL_ACCOUNT"] }
				]
				users: [ {user: "public", password: "pwd"} ]
			},

			INTERNAL_ACCOUNT: {
				jetstream: enabled
				imports: [
					{ service: { account: "PUBLIC_ACCOUNT", subject: "$JS.API.CONSUMER.CREATE.S.*.public.a" }, to: "JS.PUBLIC_ACCOUNT.CONSUMER.CREATE.S.*.public.a" },
					{ service: { account: "PUBLIC_ACCOUNT", subject: "$JS.API.CONSUMER.CREATE.S.*.public.b" }, to: "JS.PUBLIC_ACCOUNT.CONSUMER.CREATE.S.*.public.b" },
					{ service: { account: "PUBLIC_ACCOUNT", subject: "$JS.API.CONSUMER.CREATE.S.*.public.c" }, to: "JS.PUBLIC_ACCOUNT.CONSUMER.CREATE.S.*.public.c" },
					{ service: { account: "PUBLIC_ACCOUNT", subject: "$JS.FC.>" }, to: "$JS.FC.>" },
					{ stream: { account: "PUBLIC_ACCOUNT", subject: "shared.public.>" }, to: "shared.public.>" }
				]
				users: [ {user: "internal", password: "pwd"} ]
			}
		}
	`, t.TempDir()))
	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	pc, pjs := jsClientConnect(t, s, nats.UserInfo("public", "pwd"))
	defer pc.Close()

	_, err := pjs.AddStream(&nats.StreamConfig{
		Name:     "S",
		Subjects: []string{"public.>"},
	})
	require_NoError(t, err)

	ic, ijs := jsClientConnect(t, s, nats.UserInfo("internal", "pwd"))
	defer ic.Close()

	addStream := func(name, fs string, transform *nats.SubjectTransformConfig) {
		t.Helper()
		sc := &nats.StreamConfig{
			Name: name,
			Mirror: &nats.StreamSource{
				Name: "S",
				External: &nats.ExternalStream{
					APIPrefix:     "JS.PUBLIC_ACCOUNT",
					DeliverPrefix: "shared.public",
				},
			},
		}
		if fs != _EMPTY_ {
			sc.Mirror.FilterSubject = fs
		} else {
			sc.Mirror.SubjectTransforms = append(sc.Mirror.SubjectTransforms, *transform)
		}
		_, err = ijs.AddStream(sc)
		require_NoError(t, err)
	}

	checkMirror := func(name string, expected int) {
		t.Helper()
		checkFor(t, time.Second, 15*time.Millisecond, func() error {
			si, err := ijs.StreamInfo(name)
			if err != nil {
				return err
			}
			if n := int(si.State.Msgs); n != expected {
				return fmt.Errorf("Expected %v mirrored message, got %v", expected, n)
			}
			return nil
		})
	}

	// Just a subject filter
	addStream("M1", "public.a", nil)
	natsPub(t, pc, "public.a", []byte("hello"))
	checkMirror("M1", 1)

	// Now try with equivalent subject transform (no destination).
	addStream("M2", _EMPTY_, &nats.SubjectTransformConfig{Source: "public.b"})
	natsPub(t, pc, "public.b", []byte("hello"))
	checkMirror("M2", 1)

	// And now with a transform destination.
	addStream("M3", _EMPTY_, &nats.SubjectTransformConfig{Source: "public.c", Destination: "public.d"})
	natsPub(t, pc, "public.c", []byte("hello"))
	checkMirror("M3", 1)

	checkMsg := func(stream, subj string, seq uint64) {
		t.Helper()
		msg, err := ijs.GetMsg(stream, seq)
		require_NoError(t, err)
		require_Equal(t, msg.Subject, subj)
	}
	checkMsg("M1", "public.a", 1)
	checkMsg("M2", "public.b", 2)
	checkMsg("M3", "public.d", 3)

	ic.Close()
	pc.Close()
	s.Shutdown()
	s, _ = RunServerWithConfig(conf)
	defer s.Shutdown()

	ic, ijs = jsClientConnect(t, s, nats.UserInfo("internal", "pwd"))
	defer ic.Close()

	checkMirror("M1", 1)
	checkMirror("M2", 1)
	checkMirror("M3", 1)
	checkMsg("M1", "public.a", 1)
	checkMsg("M2", "public.b", 2)
	checkMsg("M3", "public.d", 3)

	pc, _ = jsClientConnect(t, s, nats.UserInfo("public", "pwd"))
	defer pc.Close()
	natsPub(t, pc, "public.a", []byte("hello"))
	natsPub(t, pc, "public.b", []byte("hello"))
	natsPub(t, pc, "public.c", []byte("hello"))
	natsFlush(t, pc)

	checkMirror("M1", 2)
	checkMirror("M2", 2)
	checkMirror("M3", 2)
	checkMsg("M1", "public.a", 1)
	checkMsg("M2", "public.b", 2)
	checkMsg("M3", "public.d", 3)
	checkMsg("M1", "public.a", 4)
	checkMsg("M2", "public.b", 5)
	checkMsg("M3", "public.d", 6)
}

func TestJetStreamFileStoreFirstSeqAfterRestart(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	// Create a stream with a first sequence.
	fseq := uint64(10_000)
	si, err := js.AddStream(&nats.StreamConfig{
		Name:      "TEST",
		Subjects:  []string{"foo"},
		Storage:   nats.FileStorage,
		Retention: nats.LimitsPolicy,
		FirstSeq:  fseq,
	})
	require_NoError(t, err)
	require_Equal(t, si.State.FirstSeq, fseq)
	require_Equal(t, si.State.LastSeq, fseq-1)

	// Publish one message to have some data in the stream.
	pubAck, err := js.Publish("foo", nil)
	require_NoError(t, err)
	require_Equal(t, pubAck.Sequence, fseq)

	// Confirm initial stream state.
	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 1)
	require_Equal(t, si.State.FirstSeq, fseq)
	require_Equal(t, si.State.LastSeq, fseq)

	// Restart the server.
	sd := s.JetStreamConfig().StoreDir
	s.Shutdown()
	nc.Close()

	s = RunJetStreamServerOnPort(-1, sd)
	defer s.Shutdown()
	nc, js = jsClientConnect(t, s)
	defer nc.Close()

	// Stream should come back up with the same state prior to restart.
	si, err = js.StreamInfo("TEST")
	require_NoError(t, err)
	require_Equal(t, si.State.Msgs, 1)
	require_Equal(t, si.State.FirstSeq, fseq)
	require_Equal(t, si.State.LastSeq, fseq)
}

func TestJetStreamCreateStreamWithSubjectDeleteMarkersOptions(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	cfg := StreamConfig{
		Name:                   "PEDANTIC",
		Storage:                FileStorage,
		Subjects:               []string{"pedantic"},
		SubjectDeleteMarkerTTL: -time.Millisecond,
	}

	_, err := addStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, true})
	require_Error(t, err, errors.New("subject delete marker TTL must not be negative"))

	cfg.SubjectDeleteMarkerTTL = time.Millisecond
	_, err = addStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, true})
	require_Error(t, err, errors.New("subject delete marker TTL must be at least 1 second"))

	cfg.SubjectDeleteMarkerTTL = time.Second
	_, err = addStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, true})
	require_Error(t, err, errors.New("subject delete marker cannot be set if message TTLs are disabled"))

	cfg.AllowMsgTTL = true
	_, err = addStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, true})
	require_Error(t, err, errors.New("subject delete marker cannot be set if roll-ups are disabled"))

	cfg.AllowRollup = true
	cfg.DenyPurge = true
	_, err = addStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, true})
	require_Error(t, err, errors.New("roll-ups require the purge permission"))

	cfg.DenyPurge = false
	_, err = addStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, true})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Automatically setup pre-requisites for SDM.
	cfg = StreamConfig{
		Name:                   "AUTO",
		Storage:                FileStorage,
		Subjects:               []string{"auto"},
		SubjectDeleteMarkerTTL: time.Second,
	}

	si, err := addStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, false})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	require_Equal(t, si.Config.SubjectDeleteMarkerTTL, time.Second)
	require_True(t, si.Config.AllowMsgTTL)
	require_True(t, si.Config.AllowRollup)
	require_False(t, si.Config.DenyPurge)

	// Allow updating to use SDM and TTL.
	cfg = StreamConfig{
		Name:     "UPDATE",
		Storage:  FileStorage,
		Subjects: []string{"update"},
	}

	si, err = addStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, false})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	require_False(t, si.Config.AllowMsgTTL)
	require_False(t, si.Config.AllowRollup)
	require_False(t, si.Config.DenyPurge)

	cfg.SubjectDeleteMarkerTTL = time.Second
	si, err = updateStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, false})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	require_Equal(t, si.Config.SubjectDeleteMarkerTTL, time.Second)
	require_True(t, si.Config.AllowMsgTTL)
	require_True(t, si.Config.AllowRollup)
	require_False(t, si.Config.DenyPurge)

	// Should not be allowed to disable msg TTL.
	cfg = si.Config
	cfg.SubjectDeleteMarkerTTL = 0
	cfg.AllowMsgTTL = false
	_, err = updateStreamPedanticWithError(t, nc, &StreamConfigRequest{cfg, true})
	require_Error(t, err, errors.New("message TTL status can not be disabled"))
}

func TestJetStreamTHWExpireTasksRace(t *testing.T) {
	for _, storageType := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storageType.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := jsStreamCreate(t, nc, &StreamConfig{
				Name:        "TEST",
				Storage:     storageType,
				Subjects:    []string{"foo"},
				AllowMsgTTL: true,
			})
			require_NoError(t, err)

			acc, err := s.lookupAccount(globalAccountName)
			require_NoError(t, err)
			mset, err := acc.lookupStream("TEST")
			require_NoError(t, err)

			// Send a bunch of message that need to be expired.
			m := nats.NewMsg("foo")
			m.Header.Set(JSMessageTTL, "1s")
			for i := 0; i < 10_000; i++ {
				_, err = js.PublishMsg(m)
				require_NoError(t, err)
			}

			// Manually lock so that expirations can't be done without us unlocking.
			if fs, ok := mset.store.(*fileStore); ok {
				fs.mu.Lock()
			} else if ms, ok := mset.store.(*memStore); ok {
				ms.mu.Lock()
			}

			// Wait for all message TTLs to have expired.
			time.Sleep(1500 * time.Millisecond)

			// Spawn a number of goroutines that will all want to lock and unlock the store lock.
			n := 50
			var ready sync.WaitGroup
			var wg sync.WaitGroup
			ready.Add(n)
			wg.Add(n)
			for i := 0; i < n; i++ {
				go func() {
					defer wg.Done()
					ready.Done()
					if fs, ok := mset.store.(*fileStore); ok {
						fs.expireMsgs()
					} else if ms, ok := mset.store.(*memStore); ok {
						ms.expireMsgs()
					}
				}()
			}

			// Wait for all goroutines to be ready.
			ready.Wait()

			// Manually unlock so that goroutines can run expirations in parallel.
			if fs, ok := mset.store.(*fileStore); ok {
				fs.mu.Unlock()
			} else if ms, ok := mset.store.(*memStore); ok {
				ms.mu.Unlock()
			}

			// Wait for all goroutines to finish.
			wg.Wait()

			// Run once more to clean up for removed messages.
			if fs, ok := mset.store.(*fileStore); ok {
				fs.expireMsgs()
			} else if ms, ok := mset.store.(*memStore); ok {
				ms.expireMsgs()
			}

			// Count of entries in the THW should be exactly 0, and not underflow.
			var hwCount uint64
			if fs, ok := mset.store.(*fileStore); ok {
				fs.mu.Lock()
				hwCount = fs.ttls.Count()
				fs.mu.Unlock()
			} else if ms, ok := mset.store.(*memStore); ok {
				ms.mu.Lock()
				hwCount = ms.ttls.Count()
				ms.mu.Unlock()
			}
			require_Equal(t, hwCount, 0)
		})
	}
}

func TestJetStreamRejectLargePublishes(t *testing.T) {
	tdir := t.TempDir()

	// The test relies on the MaxPayload being larger than the
	// rlBadThresh, otherwise you can't publish a message large
	// enough.
	conf := createConfFile(t, []byte(fmt.Sprintf(`
		listen: 127.0.0.1:-1
		max_payload: %d
		jetstream: {store_dir: %q}
	`, rlBadThresh+2048, tdir)))

	s, _ := RunServerWithConfig(conf)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:     "TEST",
		Subjects: []string{"test"},
	})
	require_NoError(t, err)

	_, err = js.Publish("test", make([]byte, rlBadThresh-1024))
	require_NoError(t, err)

	_, err = js.Publish("test", make([]byte, rlBadThresh+1024))
	require_Error(t, err)
	require_Contains(t, err.Error(), ErrMsgTooLarge.Error())
}

func TestJetStreamDirectGetSubjectDeleteMarker(t *testing.T) {
	for _, storageType := range []nats.StorageType{nats.FileStorage, nats.MemoryStorage} {
		t.Run(storageType.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := js.AddStream(&nats.StreamConfig{
				Name:                   "TEST",
				Subjects:               []string{"test"},
				Storage:                storageType,
				SubjectDeleteMarkerTTL: time.Second,
				AllowMsgTTL:            true,
				AllowDirect:            true,
			})
			require_NoError(t, err)

			m := nats.NewMsg("test")
			m.Header.Set(JSMessageTTL, "1s")
			_, err = js.PublishMsg(m)
			require_NoError(t, err)

			first, err := js.GetLastMsg("TEST", "test", nats.DirectGet())
			require_NoError(t, err)
			require_Equal(t, first.Header.Get(JSSequence), "1")

			time.Sleep(1500 * time.Millisecond)

			second, err := js.GetLastMsg("TEST", "test", nats.DirectGet())
			require_NoError(t, err)
			require_Equal(t, second.Header.Get(JSSequence), "2")
		})
	}
}

func TestJetStreamPurgeExSeqSimple(t *testing.T) {
	for _, storageType := range []nats.StorageType{nats.FileStorage, nats.MemoryStorage} {
		t.Run(storageType.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := js.AddStream(&nats.StreamConfig{
				Name:     "TEST",
				Subjects: []string{"test"},
				Storage:  storageType,
			})
			require_NoError(t, err)

			data := make([]byte, 1024)
			for i := 0; i < 10_000; i++ {
				_, err = js.Publish("test", data)
				require_NoError(t, err)
			}

			si, err := js.StreamInfo("TEST")
			require_NoError(t, err)
			require_Equal(t, si.State.Msgs, 10_000)

			require_NoError(t, js.PurgeStream("TEST", &nats.StreamPurgeRequest{Sequence: 9_000}))

			si, err = js.StreamInfo("TEST")
			require_NoError(t, err)
			require_Equal(t, si.State.Msgs, 1_001)
			require_Equal(t, si.State.NumDeleted, 0)
			require_Equal(t, si.State.FirstSeq, 9_000)
			require_Equal(t, si.State.LastSeq, 10_000)
		})
	}
}

func TestJetStreamPurgeExSeqInInteriorDeleteGap(t *testing.T) {
	for _, storageType := range []nats.StorageType{nats.FileStorage, nats.MemoryStorage} {
		t.Run(storageType.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := js.AddStream(&nats.StreamConfig{
				Name:     "TEST",
				Subjects: []string{"test.*"},
				Storage:  storageType,
			})
			require_NoError(t, err)

			data := make([]byte, 1024)
			_, err = js.Publish("test.start", data)
			require_NoError(t, err)
			for i := 0; i < 10_000; i++ {
				_, err = js.Publish("test.mid", data)
				require_NoError(t, err)
			}
			_, err = js.Publish("test.end", data)
			require_NoError(t, err)

			si, err := js.StreamInfo("TEST")
			require_NoError(t, err)
			require_Equal(t, si.State.Msgs, 10_002)

			require_NoError(t, js.PurgeStream("TEST", &nats.StreamPurgeRequest{Subject: "test.mid"}))

			si, err = js.StreamInfo("TEST")
			require_NoError(t, err)
			require_Equal(t, si.State.Msgs, 2)
			require_Equal(t, si.State.NumDeleted, 10_000)

			require_NoError(t, js.PurgeStream("TEST", &nats.StreamPurgeRequest{Sequence: 9_000}))

			si, err = js.StreamInfo("TEST")
			require_NoError(t, err)
			require_Equal(t, si.State.Msgs, 1)
			require_Equal(t, si.State.NumDeleted, 0)
			require_Equal(t, si.State.FirstSeq, 10_002)
			require_Equal(t, si.State.LastSeq, 10_002)
		})
	}
}

func TestJetStreamDirectGetUpToTime(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo"},
		AllowDirect: true,
		Storage:     nats.FileStorage,
	})
	require_NoError(t, err)

	for i := range 10 {
		sendStreamMsg(t, nc, "foo", fmt.Sprintf("message %d", i+1))
	}

	sendRequest := func(mreq *JSApiMsgGetRequest) *nats.Subscription {
		t.Helper()
		req, err := json.Marshal(mreq)
		require_NoError(t, err)
		reply := nats.NewInbox()
		sub, err := nc.SubscribeSync(reply)
		require_NoError(t, err)
		require_NoError(t, nc.PublishRequest("$JS.API.DIRECT.GET.TEST", reply, req))
		return sub
	}

	checkResponses := func(t *testing.T, upToTime time.Time, expected ...string) {
		t.Helper()
		sub := sendRequest(&JSApiMsgGetRequest{MultiLastFor: []string{"foo"}, UpToTime: &upToTime})
		defer sub.Unsubscribe()
		for _, expect := range expected {
			msg, err := sub.NextMsg(25 * time.Millisecond)
			require_NoError(t, err)
			require_Equal(t, msg.Header.Get(JSSubject), "foo")
			require_Equal(t, bytesToString(msg.Data), expect)
		}
		// By this time we're either at the end of our expected and looking
		// for an EOB marker (204) or we're not finding anything (404).
		msg, err := sub.NextMsg(25 * time.Millisecond)
		require_NoError(t, err)
		if len(expected) == 0 {
			require_Equal(t, msg.Header.Get("Status"), "404")
		} else {
			require_Equal(t, msg.Header.Get("Status"), "204")
		}
	}

	t.Run("DistantPast", func(t *testing.T) {
		checkResponses(t, time.Time{})
	})

	t.Run("DistantFuture", func(t *testing.T) {
		checkResponses(t, time.Unix(0, math.MaxInt64), "message 10")
	})

	t.Run("BeforeFirstSeq", func(t *testing.T) {
		first, err := js.GetMsg("TEST", 1)
		require_NoError(t, err)
		checkResponses(t, first.Time)
	})

	t.Run("BeforeFifthSeq", func(t *testing.T) {
		fifth, err := js.GetMsg("TEST", 5)
		require_NoError(t, err)
		checkResponses(t, fifth.Time, "message 4")
	})
}

func TestJetStreamDirectGetStartTimeSingleMsg(t *testing.T) {
	for _, storage := range []nats.StorageType{nats.FileStorage, nats.MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := js.AddStream(&nats.StreamConfig{
				Name:        "TEST",
				Subjects:    []string{"foo"},
				AllowDirect: true,
				Storage:     storage,
			})
			require_NoError(t, err)

			sendStreamMsg(t, nc, "foo", "message")

			sendRequest := func(mreq *JSApiMsgGetRequest) *nats.Subscription {
				t.Helper()
				req, err := json.Marshal(mreq)
				require_NoError(t, err)
				reply := nats.NewInbox()
				sub, err := nc.SubscribeSync(reply)
				require_NoError(t, err)
				require_NoError(t, nc.PublishRequest("$JS.API.DIRECT.GET.TEST", reply, req))
				return sub
			}

			first, err := js.GetMsg("TEST", 1)
			require_NoError(t, err)

			future := first.Time.Add(10 * time.Second)
			sub := sendRequest(&JSApiMsgGetRequest{StartTime: &future, NextFor: "foo", Batch: 1})
			defer sub.Unsubscribe()

			msg, err := sub.NextMsg(25 * time.Millisecond)
			require_NoError(t, err)
			require_Equal(t, msg.Header.Get("Status"), "404")
		})
	}
}

func TestJetStreamStreamRetentionUpdatesConsumers(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	for _, tc := range []struct {
		from RetentionPolicy
		to   RetentionPolicy
	}{
		{LimitsPolicy, InterestPolicy},
		{InterestPolicy, LimitsPolicy},
	} {
		from, to, name := tc.from, tc.to, fmt.Sprintf("%sTo%s", tc.from, tc.to)
		t.Run(name, func(t *testing.T) {
			sc, err := jsStreamCreate(t, nc, &StreamConfig{
				Name:      name,
				Subjects:  []string{name},
				Retention: from,
				Storage:   FileStorage,
			})
			require_NoError(t, err)

			_, err = js.AddConsumer(name, &nats.ConsumerConfig{
				Name:      "test_consumer",
				AckPolicy: nats.AckExplicitPolicy,
			})
			require_NoError(t, err)

			mset, err := s.globalAccount().lookupStream(name)
			require_NoError(t, err)

			o := mset.lookupConsumer("test_consumer")
			require_NotNil(t, err)
			require_Equal(t, o.retention, from)

			sc.Retention = to
			_, err = jsStreamUpdate(t, nc, sc)
			require_NoError(t, err)

			require_Equal(t, o.retention, to)
		})
	}
}

func TestJetStreamMaxMsgsPerSubjectAndDeliverLastPerSubject(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	const subjects = 300
	const msgs = subjects * 10

	_, err := js.AddStream(&nats.StreamConfig{
		Name:              "test",
		Subjects:          []string{"foo.>", "bar.>"},
		Retention:         nats.LimitsPolicy,
		Storage:           nats.FileStorage,
		MaxMsgsPerSubject: 5,
	})
	require_NoError(t, err)

	// First, publish some messages that match the consumer filter. These
	// are the messages that we expect to consume a subset of. The random
	// sequences give us interior gaps after MaxMsgsPerSubject has been
	// enforced which is needed for this test to work.
	for range msgs {
		subj := fmt.Sprintf("foo.%d", rand.Intn(subjects))
		_, err = js.Publish(subj, nil)
		require_NoError(t, err)
	}

	// Then publish some messages on a different subject. These won't be
	// matched by the consumer filter.
	for range msgs / 10 {
		subj := fmt.Sprintf("bar.%d", rand.Intn(subjects/10))
		_, err = js.Publish(subj, nil)
		require_NoError(t, err)
	}

	// Add a deliver last per consumer that matches the first batch of
	// published messages only. We expect at this point that the skiplist
	// of the consumer will be for foo.> messages only, but the resume
	// sequence will be the stream last sequence at the time, i.e. the
	// last bar.> message.
	_, err = js.AddConsumer("test", &nats.ConsumerConfig{
		Name:           "test_consumer",
		FilterSubjects: []string{"foo.>"},
		DeliverPolicy:  nats.DeliverLastPerSubjectPolicy,
		AckPolicy:      nats.AckExplicitPolicy,
	})
	require_NoError(t, err)

	// Take a copy of the skiplist and the resume value so that we can
	// make sure we receive all the messages we expect.
	mset, err := s.globalAccount().lookupStream("test")
	require_NoError(t, err)
	o := mset.lookupConsumer("test_consumer")
	o.mu.RLock()
	pending := make(map[uint64]struct{}, len(o.lss.seqs))
	for _, seq := range o.lss.seqs {
		pending[seq] = struct{}{}
	}
	resume := o.lss.resume
	o.mu.RUnlock()

	// Now fetch the messages from the consumer.
	ps, err := js.PullSubscribe(_EMPTY_, _EMPTY_, nats.Bind("test", "test_consumer"))
	require_NoError(t, err)
	for range subjects {
		msgs, err := ps.Fetch(1)
		require_NoError(t, err)
		for _, msg := range msgs {
			meta, err := msg.Metadata()
			require_NoError(t, err)
			// We must be expecting this sequence and not have seen it already.
			// Once we've seen it, take it out of the map.
			_, ok := pending[meta.Sequence.Stream]
			require_True(t, ok)
			delete(pending, meta.Sequence.Stream)
			// Then ack.
			require_NoError(t, msg.AckSync())
		}
	}

	// We should have received every message that was in the skiplist.
	require_Len(t, len(pending), 0)

	// When we've run out of last sequences per subject, the consumer
	// should now continue from the resume seq, i.e. the last bar.> message.
	o.mu.RLock()
	sseq := o.sseq
	o.mu.RUnlock()
	require_Equal(t, sseq, resume+1)
}

func TestJetStreamAllowMsgCounter(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		var servers []*Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			servers = []*Server{s}
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", 3)
			defer c.shutdown()
			servers = c.servers
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		cfg := &StreamConfig{
			Name:            "TEST",
			Subjects:        []string{"foo"},
			Storage:         FileStorage,
			AllowMsgCounter: false,
			Replicas:        replicas,
		}

		_, err := jsStreamCreate(t, nc, cfg)
		require_NoError(t, err)

		// A normal publish will succeed, as it's not a counter.
		m := nats.NewMsg("foo")
		m.Header.Set("Key", "Value")
		pa, err := js.PublishMsg(m)
		require_NoError(t, err)
		require_Equal(t, pa.Sequence, 1)

		// Stream with disabled counters doesn't allow to publish counters.
		m = nats.NewMsg("foo")
		m.Header.Set("Nats-Incr", "1")
		_, err = js.PublishMsg(m)
		require_Error(t, err, NewJSMessageIncrDisabledError())

		// Enabling counters is not allowed.
		cfg.AllowMsgCounter = true
		_, err = jsStreamUpdate(t, nc, cfg)
		require_Error(t, err, NewJSStreamInvalidConfigError(fmt.Errorf("stream configuration update can not change message counter setting")))

		// Recreate stream with counters enabled.
		require_NoError(t, js.DeleteStream("TEST"))
		_, err = jsStreamCreate(t, nc, cfg)
		require_NoError(t, err)

		// Don't allow if missing counter increment.
		m = nats.NewMsg("foo")
		_, err = js.PublishMsg(m)
		require_Error(t, err, NewJSMessageIncrMissingError())

		m.Header.Set("Key", "Value")
		_, err = js.PublishMsg(m)
		require_Error(t, err, NewJSMessageIncrMissingError())

		// Don't allow if increment contains payload.
		m.Header.Set("Nats-Incr", "1")
		m.Data = []byte("data")
		_, err = js.PublishMsg(m)
		require_Error(t, err, NewJSMessageIncrPayloadError())

		// Don't allow if counter increment is invalid.
		m = nats.NewMsg("foo")
		m.Header.Set("Nats-Incr", "bogus")
		_, err = js.PublishMsg(m)
		require_Error(t, err, NewJSMessageIncrInvalidError())

		validateTotal := func(seq uint64, total *big.Int) {
			t.Helper()
			rsm, err := js.GetLastMsg("TEST", "foo")
			require_NoError(t, err)
			require_Equal(t, rsm.Sequence, seq)

			var val CounterValue
			require_NoError(t, json.Unmarshal(rsm.Data, &val))
			var res big.Int
			res.SetString(val.Value, 10)
			require_Equal(t, res.Int64(), total.Int64())
		}

		increment := func(incr string, seq uint64, total *big.Int) {
			t.Helper()
			m = nats.NewMsg("foo")
			m.Header.Set("Nats-Incr", incr)

			msg, err := nc.RequestMsg(m, time.Second)
			require_NoError(t, err)
			var pubAck PubAck
			require_NoError(t, json.Unmarshal(msg.Data, &pubAck))
			require_Equal(t, pubAck.Sequence, seq)
			require_Equal(t, pubAck.Value, total.String())
			validateTotal(seq, total)
		}

		// Perform and check increments.
		increment("1", 1, big.NewInt(1))
		increment("2", 2, big.NewInt(3))

		// Can also decrement/reset the counter.
		increment("-3", 3, big.NewInt(0))
		increment("1", 4, big.NewInt(1))

		// Reset back to zero.
		increment("-1", 5, big.NewInt(0))

		// Check de-duplication.
		m = nats.NewMsg("foo")
		m.Header.Set("Nats-Incr", "1")
		m.Header.Set("Nats-Msg-Id", "dedupe")
		msg, err := nc.RequestMsg(m, time.Second)
		require_NoError(t, err)
		var pubAck1 PubAck
		require_NoError(t, json.Unmarshal(msg.Data, &pubAck1))
		require_False(t, pubAck1.Duplicate)
		require_Equal(t, pubAck1.Sequence, 6)
		require_Equal(t, pubAck1.Value, "1")
		validateTotal(6, big.NewInt(1))

		// Re-send should not up counter, but also not return current value.
		// When clustered this state can't be guaranteed.
		msg, err = nc.RequestMsg(m, time.Second)
		require_NoError(t, err)
		var pubAck2 PubAck
		require_NoError(t, json.Unmarshal(msg.Data, &pubAck2))
		require_True(t, pubAck2.Duplicate)
		require_Equal(t, pubAck2.Sequence, 6)
		require_Equal(t, pubAck2.Value, _EMPTY_)
		validateTotal(6, big.NewInt(1))

		// Check rejected headers.
		for _, header := range []string{JSMsgRollup, JSExpectedLastSeq, JSExpectedLastSubjSeq, JSExpectedLastSubjSeqSubj, JSExpectedLastMsgId} {
			m = nats.NewMsg("foo")
			m.Header.Set("Nats-Incr", "1")
			m.Header.Set(header, "1")
			_, err = js.PublishMsg(m)
			require_Error(t, err, NewJSMessageIncrInvalidError())
		}

		// Manually break a counter in storage.
		for _, cs := range servers {
			mset, err := cs.globalAccount().lookupStream("TEST")
			require_NoError(t, err)
			seq, _, err := mset.Store().StoreMsg("foo", nil, nil, 0)
			require_NoError(t, err)
			require_Equal(t, seq, 7)
		}

		// Should now error, because counter is broken.
		m = nats.NewMsg("foo")
		m.Header.Set("Nats-Incr", "1")
		_, err = js.PublishMsg(m)
		require_Error(t, err, NewJSMessageCounterBrokenError())
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamAllowMsgCounterMaxPayloadAndSize(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			s.optsMu.Lock()
			s.opts.MaxPayload = 1024
			s.optsMu.Unlock()
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", 3)
			defer c.shutdown()
			for _, cs := range c.servers {
				cs.optsMu.Lock()
				cs.opts.MaxPayload = 1024
				cs.optsMu.Unlock()
			}
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		cfg := &StreamConfig{
			Name:            "TEST",
			Subjects:        []string{"foo"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		}
		_, err := jsStreamCreate(t, nc, cfg)
		require_NoError(t, err)

		validateTotal := func(seq uint64, total *big.Int) {
			t.Helper()
			rsm, err := js.GetLastMsg("TEST", "foo")
			require_NoError(t, err)
			require_Equal(t, rsm.Sequence, seq)

			var val CounterValue
			require_NoError(t, json.Unmarshal(rsm.Data, &val))
			var res big.Int
			res.SetString(val.Value, 10)
			require_Equal(t, res.Int64(), total.Int64())
		}

		increment := func(incr string, seq uint64, total *big.Int) {
			t.Helper()
			m := nats.NewMsg("foo")
			m.Header.Set("Nats-Incr", incr)

			msg, err := nc.RequestMsg(m, time.Second)
			require_NoError(t, err)
			var pubAck PubAck
			require_NoError(t, json.Unmarshal(msg.Data, &pubAck))
			require_Equal(t, pubAck.Sequence, seq)
			require_Equal(t, pubAck.Value, total.String())
			validateTotal(seq, total)
		}

		// Check payload exceeded, positive bound.
		increment("1", 1, big.NewInt(1))
		tooLargeIncrement := strings.Repeat("1", 500)
		m := nats.NewMsg("foo")
		m.Header.Set("Nats-Incr", tooLargeIncrement)
		_, err = js.PublishMsg(m)
		require_Error(t, err, NewJSStreamMessageExceedsMaximumError())

		// Check payload exceeded, negative bound.
		increment("-2", 2, big.NewInt(-1))
		m.Header.Set("Nats-Incr", fmt.Sprintf("-%s", tooLargeIncrement))
		_, err = js.PublishMsg(m)
		require_Error(t, err, NewJSStreamMessageExceedsMaximumError())

		// Reset back to zero.
		increment("1", 3, big.NewInt(0))

		// Exactly equals the size of the message for the first message.
		cfg.MaxMsgSize = 37
		_, err = jsStreamUpdate(t, nc, cfg)
		require_NoError(t, err)
		increment("1", 4, big.NewInt(1))

		// Next increment bumps over MaxMsgSize limit defined above.
		m.Header.Set("Nats-Incr", "10")
		_, err = js.PublishMsg(m)
		require_Error(t, err, NewJSStreamMessageExceedsMaximumError())
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamAllowMsgCounterIncompatibleSettings(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	// DiscardNew not allowed.
	_, err := jsStreamCreate(t, nc, &StreamConfig{
		Name:            "TEST",
		Subjects:        []string{"foo"},
		Storage:         FileStorage,
		AllowMsgCounter: true,
		Discard:         DiscardNew,
	})
	require_Error(t, err, NewJSStreamInvalidConfigError(fmt.Errorf("counter stream cannot use discard new")))

	// AllowMsgTTL not allowed.
	_, err = jsStreamCreate(t, nc, &StreamConfig{
		Name:            "TEST",
		Subjects:        []string{"foo"},
		Storage:         FileStorage,
		AllowMsgCounter: true,
		AllowMsgTTL:     true,
	})
	require_Error(t, err, NewJSStreamInvalidConfigError(fmt.Errorf("counter stream cannot use message TTLs")))

	// Only limits retention is allowed.
	for _, retention := range []RetentionPolicy{InterestPolicy, WorkQueuePolicy} {
		_, err = jsStreamCreate(t, nc, &StreamConfig{
			Name:            "TEST",
			Subjects:        []string{"foo"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Retention:       retention,
		})
		require_Error(t, err, NewJSStreamInvalidConfigError(fmt.Errorf("counter stream can only use limits retention")))
	}
}

func TestJetStreamAllowMsgCounterMirror(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", 3)
			defer c.shutdown()
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		_, err := jsStreamCreate(t, nc, &StreamConfig{
			Name:            "O",
			Subjects:        []string{"foo"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		})
		require_NoError(t, err)

		// Mirror with counters enabled is rejected.
		mirrorCfg := &StreamConfig{
			Name:            "M",
			Mirror:          &StreamSource{Name: "O"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		}
		_, err = jsStreamCreate(t, nc, mirrorCfg)
		require_Error(t, err, NewJSMirrorWithCountersError())

		// Mirror with verbatim copying of counters.
		mirrorCfg.AllowMsgCounter = false
		_, err = jsStreamCreate(t, nc, mirrorCfg)
		require_NoError(t, err)

		// A normal publish will succeed, as it's not a counter.
		m := nats.NewMsg("foo")
		m.Header.Set("Nats-Incr", "1")
		pubAck, err := js.PublishMsg(m)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 1)

		// Mirror should get message verbatim.
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			rsm, err := js.GetMsg("M", 1)
			if err != nil {
				return err
			}
			if incr := rsm.Header.Get("Nats-Incr"); incr != "1" {
				return fmt.Errorf("incorrect increment: %q", incr)
			}
			var count CounterValue
			if err := json.Unmarshal(rsm.Data, &count); err != nil {
				return fmt.Errorf("JSON error: %w", err)
			} else if count.Value != "1" {
				return fmt.Errorf("unexpected value: %s", rsm.Data)
			}
			return nil
		})
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamAllowMsgCounterSourceAggregates(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", 3)
			defer c.shutdown()
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		_, err := jsStreamCreate(t, nc, &StreamConfig{
			Name:            "O1",
			Subjects:        []string{"foo.1"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		})
		require_NoError(t, err)

		_, err = jsStreamCreate(t, nc, &StreamConfig{
			Name:            "O2",
			Subjects:        []string{"foo.2"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		})
		require_NoError(t, err)

		// Source will only work if counters are enabled on both streams.
		sourceCfg := &StreamConfig{
			Name: "M",
			Sources: []*StreamSource{
				{
					Name:              "O1",
					SubjectTransforms: []SubjectTransformConfig{{Source: "foo.*", Destination: "foo"}},
				},
				{
					Name:              "O2",
					SubjectTransforms: []SubjectTransformConfig{{Source: "foo.*", Destination: "foo"}},
				},
			},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		}
		_, err = jsStreamCreate(t, nc, sourceCfg)
		require_NoError(t, err)

		m := nats.NewMsg("foo.1")
		m.Header.Set("Nats-Incr", "1")
		pubAck, err := js.PublishMsg(m)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 1)

		m = nats.NewMsg("foo.2")
		m.Header.Set("Nats-Incr", "2")
		pubAck, err = js.PublishMsg(m)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 1)

		// Source should aggregate.
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			rsm, err := js.GetMsg("M", 2)
			if err != nil {
				return err
			}
			var count CounterValue
			if err := json.Unmarshal(rsm.Data, &count); err != nil {
				return fmt.Errorf("JSON error: %w", err)
			} else if count.Value != "3" {
				return fmt.Errorf("unexpected value: %s", rsm.Data)
			}
			return nil
		})
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamAllowMsgCounterSourceVerbatim(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", 3)
			defer c.shutdown()
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		_, err := jsStreamCreate(t, nc, &StreamConfig{
			Name:            "O1",
			Subjects:        []string{"foo.1"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		})
		require_NoError(t, err)

		_, err = jsStreamCreate(t, nc, &StreamConfig{
			Name:            "O2",
			Subjects:        []string{"foo.2"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		})
		require_NoError(t, err)

		// Source will only work if counters are enabled on both streams.
		sourceCfg := &StreamConfig{
			Name: "M",
			Sources: []*StreamSource{
				{
					Name:              "O1",
					SubjectTransforms: []SubjectTransformConfig{{Source: "foo.*", Destination: "foo"}},
				},
				{
					Name:              "O2",
					SubjectTransforms: []SubjectTransformConfig{{Source: "foo.*", Destination: "foo"}},
				},
			},
			Storage:         FileStorage,
			AllowMsgCounter: false,
			Replicas:        replicas,
		}
		_, err = jsStreamCreate(t, nc, sourceCfg)
		require_NoError(t, err)

		m := nats.NewMsg("foo.1")
		m.Header.Set("Nats-Incr", "1")
		pubAck, err := js.PublishMsg(m)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 1)

		// Source should store verbatim.
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			rsm, err := js.GetMsg("M", 1)
			if err != nil {
				return err
			}
			var count CounterValue
			if err := json.Unmarshal(rsm.Data, &count); err != nil {
				return fmt.Errorf("JSON error: %w", err)
			} else if count.Value != "1" {
				return fmt.Errorf("unexpected value: %s", rsm.Data)
			}
			return nil
		})

		m = nats.NewMsg("foo.2")
		m.Header.Set("Nats-Incr", "2")
		pubAck, err = js.PublishMsg(m)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 1)

		// Source should store verbatim.
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			rsm, err := js.GetMsg("M", 2)
			if err != nil {
				return err
			}
			var count CounterValue
			if err := json.Unmarshal(rsm.Data, &count); err != nil {
				return fmt.Errorf("JSON error: %w", err)
			} else if count.Value != "2" {
				return fmt.Errorf("unexpected value: %s", rsm.Data)
			}
			return nil
		})
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamAllowMsgCounterSourceStartingAboveZero(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", 3)
			defer c.shutdown()
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		_, err := jsStreamCreate(t, nc, &StreamConfig{
			Name:            "O1",
			Subjects:        []string{"foo.1"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
			MaxMsgsPer:      1,
		})
		require_NoError(t, err)

		_, err = jsStreamCreate(t, nc, &StreamConfig{
			Name:            "O2",
			Subjects:        []string{"foo.2"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
			MaxMsgsPer:      1,
		})
		require_NoError(t, err)

		for i := range uint64(5) {
			m := nats.NewMsg("foo.1")
			m.Header.Set("Nats-Incr", "1")
			pubAck, err := js.PublishMsg(m)
			require_NoError(t, err)
			require_Equal(t, pubAck.Sequence, i+1)

			m = nats.NewMsg("foo.2")
			m.Header.Set("Nats-Incr", "2")
			pubAck, err = js.PublishMsg(m)
			require_NoError(t, err)
			require_Equal(t, pubAck.Sequence, i+1)
		}

		// Source will only work if counters are enabled on both streams.
		_, err = jsStreamCreate(t, nc, &StreamConfig{
			Name:            "M",
			Subjects:        []string{"foo"},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		})
		require_NoError(t, err)

		// Now make an addition locally on this stream too.
		m := nats.NewMsg("foo")
		m.Header.Set("Nats-Incr", "1")
		pubAck, err := js.PublishMsg(m)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 1)

		// Source will only work if counters are enabled on both streams.
		_, err = jsStreamUpdate(t, nc, &StreamConfig{
			Name:     "M",
			Subjects: []string{"foo"},
			Sources: []*StreamSource{
				{
					Name:              "O1",
					SubjectTransforms: []SubjectTransformConfig{{Source: "foo.*", Destination: "foo"}},
				},
				{
					Name:              "O2",
					SubjectTransforms: []SubjectTransformConfig{{Source: "foo.*", Destination: "foo"}},
				},
			},
			Storage:         FileStorage,
			AllowMsgCounter: true,
			Replicas:        replicas,
		})
		require_NoError(t, err)

		// Source should aggregate.
		var first, second, third, fourth *nats.RawStreamMsg
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			first, err = js.GetMsg("M", 1)
			if err != nil {
				return err
			}
			second, err = js.GetMsg("M", 2)
			if err != nil {
				return err
			}
			third, err = js.GetMsg("M", 3)
			return err
		})

		// Now make an addition locally on this stream too.
		m = nats.NewMsg("foo")
		m.Header.Set("Nats-Incr", "1")
		pubAck, err = js.PublishMsg(m)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 4)

		// Fetch it back out of the stream.
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			fourth, err = js.GetMsg("M", 4)
			return err
		})

		// There are no local additions to this counter, but the total
		// comprises changes from the sources.
		var count CounterValue
		require_NoError(t, json.Unmarshal(fourth.Data, &count))
		require_Equal(t, count.Value, "17")

		// The most recent message should contain information about both
		// sources, so let's check.
		var sources CounterSources
		require_NoError(t, json.Unmarshal([]byte(fourth.Header.Get(JSMessageCounterSources)), &sources))
		require_NotNil(t, sources["O1"])
		require_NotNil(t, sources["O2"])
		require_Equal(t, sources["O1"]["foo.1"], "5")
		require_Equal(t, sources["O2"]["foo.2"], "10")

		// Since this is the first time we've seen a message from these
		// sources, the Nats-Incr header should have been updated to reflect
		// the correct delta.
		for _, rsm := range []*nats.RawStreamMsg{first, second, third, fourth} {
			require_Equal(t, rsm.Subject, "foo") // Subject transform'd
			switch rsm {
			case first:
				require_Equal(t, rsm.Header.Get(JSMessageIncr), "1")
			case second, third: // We can't know which order they got sourced in
				incr := rsm.Header.Get(JSMessageIncr)
				require_True(t, incr == "5" || incr == "10")
			case fourth:
				require_Equal(t, rsm.Header.Get(JSMessageIncr), "1")
			}
		}
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamGetNoHeaders(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	_, err := js.AddStream(&nats.StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo"},
		Storage:     nats.FileStorage,
		AllowDirect: true,
	})
	require_NoError(t, err)

	msg := &nats.Msg{
		Subject: "foo",
		Header: nats.Header{
			"test": []string{"something"},
		},
		Data: []byte{1, 2, 3, 4, 5},
	}
	_, err = js.PublishMsg(msg)
	require_NoError(t, err)

	t.Run("MsgGet", func(t *testing.T) {
		msgGet := func(noHeaders bool) (payload []byte, hdrs nats.Header) {
			getSubj := fmt.Sprintf(JSApiMsgGetT, "TEST")
			req := fmt.Appendf(nil, `{"seq":1,"no_hdr":%v}`, noHeaders)
			resp, err := nc.Request(getSubj, req, time.Second)
			require_NoError(t, err)
			var get JSApiMsgGetResponse
			require_NoError(t, json.Unmarshal(resp.Data, &get))
			payload = get.Message.Data
			if len(get.Message.Header) > 0 {
				hdrs, err = nats.DecodeHeadersMsg(get.Message.Header)
				require_NoError(t, err)
			}
			return
		}

		payload, headers := msgGet(false)
		require_True(t, bytes.Equal(payload, msg.Data))
		require_Equal(t, headers.Get("test"), "something")

		payload, headers = msgGet(true)
		require_True(t, bytes.Equal(payload, msg.Data))
		require_Equal(t, headers.Get("test"), _EMPTY_)
	})

	t.Run("DirectGet", func(t *testing.T) {
		directGet := func(noHeaders bool) (payload []byte, hdrs nats.Header) {
			getSubj := fmt.Sprintf(JSDirectMsgGetT, "TEST")
			req := fmt.Appendf(nil, `{"seq":1,"no_hdr":%v}`, noHeaders)
			resp, err := nc.Request(getSubj, req, time.Second)
			require_NoError(t, err)
			return resp.Data, resp.Header
		}

		payload, headers := directGet(false)
		require_True(t, bytes.Equal(payload, msg.Data))
		require_Equal(t, headers.Get("test"), "something")

		payload, headers = directGet(true)
		require_True(t, bytes.Equal(payload, msg.Data))
		require_Equal(t, headers.Get("test"), _EMPTY_)
		require_Equal(t, headers.Get("Nats-Stream"), _EMPTY_)
		require_Equal(t, headers.Get("Nats-Sequence"), _EMPTY_)
		require_Equal(t, headers.Get("Nats-Time-Stamp"), _EMPTY_)
	})

	t.Run("DirectGetLastFor", func(t *testing.T) {
		directGet := func(noHeaders bool) (payload []byte, hdrs nats.Header) {
			getSubj := fmt.Sprintf(JSDirectGetLastBySubjectT, "TEST", "foo")
			req := fmt.Appendf(nil, `{"no_hdr":%v}`, noHeaders)
			resp, err := nc.Request(getSubj, req, time.Second)
			require_NoError(t, err)
			return resp.Data, resp.Header
		}

		payload, headers := directGet(false)
		require_True(t, bytes.Equal(payload, msg.Data))
		require_Equal(t, headers.Get("test"), "something")

		payload, headers = directGet(true)
		require_True(t, bytes.Equal(payload, msg.Data))
		require_Equal(t, headers.Get("test"), _EMPTY_)
		require_Equal(t, headers.Get("Nats-Stream"), _EMPTY_)
		require_Equal(t, headers.Get("Nats-Sequence"), _EMPTY_)
		require_Equal(t, headers.Get("Nats-Time-Stamp"), _EMPTY_)
	})
}

func TestJetStreamKVNoSubjectDeleteMarkerOnPurgeMarker(t *testing.T) {
	for _, storage := range []jetstream.StorageType{jetstream.FileStorage, jetstream.MemoryStorage} {
		t.Run(storage.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnectNewAPI(t, s)
			defer nc.Close()

			ctx := context.Background()
			kv, err := js.CreateKeyValue(ctx, jetstream.KeyValueConfig{
				Bucket:         "bucket",
				History:        1,
				Storage:        storage,
				TTL:            2 * time.Second,
				LimitMarkerTTL: time.Minute,
			})
			require_NoError(t, err)

			stream, err := js.Stream(ctx, "KV_bucket")
			require_NoError(t, err)

			// Purge such that the bucket TTL expires this message.
			require_NoError(t, kv.Purge(ctx, "key"))
			rsm, err := stream.GetMsg(ctx, 1)
			require_NoError(t, err)
			require_Equal(t, rsm.Header.Get("KV-Operation"), "PURGE")

			// The bucket TTL should have removed the message by now.
			time.Sleep(2500 * time.Millisecond)

			// Confirm the purge marker is gone.
			_, err = stream.GetMsg(ctx, 1)
			require_Error(t, err, jetstream.ErrMsgNotFound)
			require_Equal(t, rsm.Header.Get("KV-Operation"), "PURGE")

			// Confirm we don't get a redundant subject delete marker.
			_, err = stream.GetMsg(ctx, 2)
			require_Error(t, err, jetstream.ErrMsgNotFound)

			// Purge with a TTL so it expires this message.
			require_NoError(t, kv.Purge(ctx, "key", jetstream.PurgeTTL(time.Second)))
			rsm, err = stream.GetMsg(ctx, 2)
			require_NoError(t, err)
			require_Equal(t, rsm.Header.Get("KV-Operation"), "PURGE")

			// The purge TTL should have removed the message by now.
			time.Sleep(1500 * time.Millisecond)

			// Confirm the purge marker is gone.
			_, err = stream.GetMsg(ctx, 2)
			require_Error(t, err, jetstream.ErrMsgNotFound)

			// Confirm we don't get a redundant subject delete marker.
			_, err = stream.GetMsg(ctx, 3)
			require_Error(t, err, jetstream.ErrMsgNotFound)
		})
	}
}

func TestJetStreamInvalidConfigValues(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	acc := s.globalAccount()

	_, err := s.checkStreamCfg(&StreamConfig{Name: "TEST", Retention: -1}, acc, false)
	require_True(t, err != nil)
	require_Error(t, err, NewJSStreamInvalidConfigError(errors.New("invalid retention")))

	_, err = s.checkStreamCfg(&StreamConfig{Name: "TEST", Discard: -1}, acc, false)
	require_True(t, err != nil)
	require_Error(t, err, NewJSStreamInvalidConfigError(errors.New("invalid discard policy")))

	_, err = s.checkStreamCfg(&StreamConfig{Name: "TEST", Storage: -1}, acc, false)
	require_True(t, err != nil)
	require_Error(t, err, NewJSStreamInvalidConfigError(errors.New("invalid storage type")))

	_, err = s.checkStreamCfg(&StreamConfig{Name: "TEST", Compression: 255}, acc, false)
	require_True(t, err != nil)
	require_Error(t, err, NewJSStreamInvalidConfigError(errors.New("invalid compression")))

	_, err = s.checkStreamCfg(&StreamConfig{Name: "TEST", MaxAge: -time.Second}, acc, false)
	require_True(t, err != nil)
	require_Error(t, err, NewJSStreamInvalidConfigError(errors.New("max age can not be negative")))

	scfg := StreamConfig{Name: "TEST"}
	streamTests := []struct {
		name     string
		setValue func(value int)
		getValue func() int
	}{
		{
			name:     "max_msgs",
			setValue: func(value int) { scfg.MaxMsgs = int64(value) },
			getValue: func() int { return int(scfg.MaxMsgs) },
		},
		{
			name:     "max_msgs_per_subject",
			setValue: func(value int) { scfg.MaxMsgsPer = int64(value) },
			getValue: func() int { return int(scfg.MaxMsgsPer) },
		},
		{
			name:     "max_bytes",
			setValue: func(value int) { scfg.MaxBytes = int64(value) },
			getValue: func() int { return int(scfg.MaxBytes) },
		},
		{
			name:     "max_msg_size",
			setValue: func(value int) { scfg.MaxMsgSize = int32(value) },
			getValue: func() int { return int(scfg.MaxMsgSize) },
		},
		{
			name:     "max_consumers",
			setValue: func(value int) { scfg.MaxConsumers = value },
			getValue: func() int { return scfg.MaxConsumers },
		},
	}
	for _, streamTest := range streamTests {
		// Pedantic errors if less than -1.
		streamTest.setValue(-10)
		_, err = s.checkStreamCfg(&scfg, acc, true)
		if err == nil {
			t.Fatal("Expected error for pedantic mode")
		}
		require_Error(t, err, NewJSPedanticError(fmt.Errorf("%s must be set to -1", streamTest.name)))

		// Pedantic defaults if zero-value.
		streamTest.setValue(0)
		scfg, err = s.checkStreamCfg(&scfg, acc, true)
		if err != nil {
			require_NoError(t, err)
		}
		require_Equal(t, streamTest.getValue(), -1)

		// Non-pedantic defaults.
		streamTest.setValue(-10)
		scfg, err = s.checkStreamCfg(&scfg, acc, false)
		if err != nil {
			require_NoError(t, err)
		}
		require_Equal(t, streamTest.getValue(), -1)
	}

	ccfg := &ConsumerConfig{AckPolicy: -1}
	err = checkConsumerCfg(ccfg, &JSLimitOpts{}, &scfg, nil, &JetStreamAccountLimits{}, false)
	require_True(t, err != nil)
	require_Error(t, err, NewJSConsumerAckPolicyInvalidError())

	ccfg = &ConsumerConfig{ReplayPolicy: -1}
	err = checkConsumerCfg(ccfg, &JSLimitOpts{}, &scfg, nil, &JetStreamAccountLimits{}, false)
	require_True(t, err != nil)
	require_Error(t, err, NewJSConsumerReplayPolicyInvalidError())

	ccfg = &ConsumerConfig{AckWait: -time.Second}
	err = checkConsumerCfg(ccfg, &JSLimitOpts{}, &scfg, nil, &JetStreamAccountLimits{}, false)
	require_True(t, err != nil)
	require_Error(t, err, NewJSConsumerAckWaitNegativeError())

	ccfg = &ConsumerConfig{BackOff: []time.Duration{-time.Second}}
	err = checkConsumerCfg(ccfg, &JSLimitOpts{}, &scfg, nil, &JetStreamAccountLimits{}, false)
	require_True(t, err != nil)
	require_Error(t, err, NewJSConsumerBackOffNegativeError())

	ccfg = &ConsumerConfig{AckPolicy: AckExplicit}
	consumerTests := []struct {
		name         string
		setValue     func(value int)
		getValue     func() int
		defaultValue int
	}{
		{
			name:         "max_deliver",
			setValue:     func(value int) { ccfg.MaxDeliver = value },
			getValue:     func() int { return ccfg.MaxDeliver },
			defaultValue: -1,
		},
		{
			name:         "max_waiting",
			setValue:     func(value int) { ccfg.MaxWaiting = value },
			getValue:     func() int { return ccfg.MaxWaiting },
			defaultValue: JSWaitQueueDefaultMax,
		},
		{
			name:         "max_batch",
			setValue:     func(value int) { ccfg.MaxRequestBatch = value },
			getValue:     func() int { return ccfg.MaxRequestBatch },
			defaultValue: 0,
		},
		{
			name:         "max_expires",
			setValue:     func(value int) { ccfg.MaxRequestExpires = time.Duration(value) },
			getValue:     func() int { return int(ccfg.MaxRequestExpires) },
			defaultValue: 0,
		},
		{
			name:         "max_bytes",
			setValue:     func(value int) { ccfg.MaxRequestMaxBytes = value },
			getValue:     func() int { return ccfg.MaxRequestMaxBytes },
			defaultValue: 0,
		},
		{
			name:         "idle_heartbeat",
			setValue:     func(value int) { ccfg.Heartbeat = time.Duration(value) },
			getValue:     func() int { return int(ccfg.Heartbeat) },
			defaultValue: 0,
		},
		{
			name:         "inactive_threshold",
			setValue:     func(value int) { ccfg.InactiveThreshold = time.Duration(value) },
			getValue:     func() int { return int(ccfg.InactiveThreshold) },
			defaultValue: 0,
		},
		{
			name:         "priority_timeout",
			setValue:     func(value int) { ccfg.PinnedTTL = time.Duration(value) },
			getValue:     func() int { return int(ccfg.PinnedTTL) },
			defaultValue: 0,
		},
	}
	for _, consumerTest := range consumerTests {
		// Pedantic errors if less than -1.
		consumerTest.setValue(-10)
		err = setConsumerConfigDefaults(ccfg, &scfg, &JSLimitOpts{}, &JetStreamAccountLimits{}, true)
		if err == nil {
			t.Fatal("Expected error for pedantic mode")
		}
		if consumerTest.defaultValue == -1 {
			require_Error(t, err, NewJSPedanticError(fmt.Errorf("%s must be set to -1", consumerTest.name)))
		} else {
			require_Error(t, err, NewJSPedanticError(fmt.Errorf("%s must not be negative", consumerTest.name)))
		}

		// Pedantic defaults if zero-value.
		consumerTest.setValue(0)
		err = setConsumerConfigDefaults(ccfg, &scfg, &JSLimitOpts{}, &JetStreamAccountLimits{}, true)
		if err != nil {
			require_NoError(t, err)
		}
		require_Equal(t, consumerTest.getValue(), consumerTest.defaultValue)

		// Non-pedantic defaults.
		consumerTest.setValue(-10)
		err = setConsumerConfigDefaults(ccfg, &scfg, &JSLimitOpts{}, &JetStreamAccountLimits{}, false)
		if err != nil {
			require_NoError(t, err)
		}
		require_Equal(t, consumerTest.getValue(), consumerTest.defaultValue)
	}

	// Pedantic errors if less than -1.
	ccfg.MaxAckPending = -10
	err = setConsumerConfigDefaults(ccfg, &scfg, &JSLimitOpts{}, &JetStreamAccountLimits{}, true)
	if err == nil {
		t.Fatal("Expected error for pedantic mode")
	}
	require_Error(t, err, NewJSPedanticError(errors.New("max_ack_pending must be set to -1")))

	// Pedantic defaults if zero-value.
	ccfg.MaxAckPending = 0
	err = setConsumerConfigDefaults(ccfg, &scfg, &JSLimitOpts{}, &JetStreamAccountLimits{}, true)
	if err != nil {
		require_NoError(t, err)
	}
	require_Equal(t, ccfg.MaxAckPending, JsDefaultMaxAckPending)

	// Non-pedantic defaults.
	ccfg.MaxAckPending = -10
	err = setConsumerConfigDefaults(ccfg, &scfg, &JSLimitOpts{}, &JetStreamAccountLimits{}, false)
	if err != nil {
		require_NoError(t, err)
	}
	require_Equal(t, ccfg.MaxAckPending, -1)
}

func TestJetStreamPromoteMirrorDeletingOrigin(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", 3)
			defer c.shutdown()
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		_, err := jsStreamCreate(t, nc, &StreamConfig{
			Name:     "O",
			Subjects: []string{"foo"},
			Storage:  FileStorage,
			Replicas: replicas,
		})
		require_NoError(t, err)

		mirrorCfg := &StreamConfig{
			Name:     "M",
			Mirror:   &StreamSource{Name: "O"},
			Storage:  FileStorage,
			Replicas: replicas,
		}
		mirrorCfg, err = jsStreamCreate(t, nc, mirrorCfg)
		require_NoError(t, err)

		pubAck, err := js.Publish("foo", nil)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 1)

		// Mirror should get message.
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			_, err := js.GetMsg("M", 1)
			return err
		})

		// Trying to promote the mirror with a subject conflict should fail
		// because the origin stream is listening on that subject still.
		mirrorCfg.Mirror = nil
		mirrorCfg.Subjects = []string{"foo"}
		_, err = jsStreamUpdate(t, nc, mirrorCfg)
		require_Error(t, err)
		apiErr, ok := err.(*ApiError)
		require_True(t, ok)
		require_Equal(t, apiErr.ErrCode, uint16(JSStreamSubjectOverlapErr))

		// But if we delete the stream, the subject conflict goes away...
		err = js.DeleteStream("O")
		require_NoError(t, err)

		// ... so now it should work.
		mirrorCfg, err = jsStreamUpdate(t, nc, mirrorCfg)
		require_NoError(t, err)
		require_Len(t, len(mirrorCfg.Subjects), 1)
		require_Equal(t, mirrorCfg.Mirror, nil)

		// Make sure the mirror state has gone away.
		checkFor(t, 5*time.Second, 200*time.Millisecond, func() error {
			si, err := js.StreamInfo("M")
			if err != nil {
				return err
			}
			if si.Mirror != nil {
				return fmt.Errorf("expecting no mirror status, got %+v", si.Mirror)
			}
			return nil
		})

		// Now we should be able to publish into the newly promoted mirror.
		pubAck, err = js.Publish("foo", nil)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 2)

		// ... and confirm that it was received in the mirror stream.
		_, err = js.GetMsg("M", 2)
		require_NoError(t, err)
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamPromoteMirrorUpdatingOrigin(t *testing.T) {
	test := func(t *testing.T, replicas int) {
		var s *Server
		if replicas == 1 {
			s = RunBasicJetStreamServer(t)
			defer s.Shutdown()
		} else {
			c := createJetStreamClusterExplicit(t, "R3S", 3)
			defer c.shutdown()
			s = c.randomServer()
		}

		nc, js := jsClientConnect(t, s)
		defer nc.Close()

		originCfg, err := jsStreamCreate(t, nc, &StreamConfig{
			Name:     "O",
			Subjects: []string{"foo"},
			Storage:  FileStorage,
			Replicas: replicas,
		})
		require_NoError(t, err)

		mirrorCfg := &StreamConfig{
			Name:     "M",
			Mirror:   &StreamSource{Name: "O"},
			Storage:  FileStorage,
			Replicas: replicas,
		}
		mirrorCfg, err = jsStreamCreate(t, nc, mirrorCfg)
		require_NoError(t, err)

		pubAck, err := js.Publish("foo", nil)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 1)

		// Mirror should get message.
		checkFor(t, 2*time.Second, 200*time.Millisecond, func() error {
			_, err := js.GetMsg("M", 1)
			return err
		})

		// Trying to promote the mirror with a subject conflict should fail
		// because the origin stream is listening on that subject still.
		mirrorCfg.Mirror = nil
		mirrorCfg.Subjects = []string{"foo"}
		_, err = jsStreamUpdate(t, nc, mirrorCfg)
		require_Error(t, err)
		apiErr, ok := err.(*ApiError)
		require_True(t, ok)
		require_Equal(t, apiErr.ErrCode, uint16(JSStreamSubjectOverlapErr))

		// But if we change the subjects on the origin stream, the subject
		// conflict goes away...
		originCfg.Subjects = []string{"bar"}
		_, err = jsStreamUpdate(t, nc, originCfg)
		require_NoError(t, err)

		// ... so now it should work.
		mirrorCfg, err = jsStreamUpdate(t, nc, mirrorCfg)
		require_NoError(t, err)
		require_Len(t, len(mirrorCfg.Subjects), 1)
		require_Equal(t, mirrorCfg.Mirror, nil)

		// Make sure the mirror state has gone away.
		checkFor(t, 5*time.Second, 200*time.Millisecond, func() error {
			si, err := js.StreamInfo("M")
			if err != nil {
				return err
			}
			if si.Mirror != nil {
				return fmt.Errorf("expecting no mirror status, got %+v", si.Mirror)
			}
			return nil
		})

		// Publishing into the original stream should no longer mirror over
		// onto the mirror stream...
		pubAck, err = js.Publish("bar", nil)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 2)

		// ... therefore a new publish to the mirror stream should also have
		// sequence 2 and not 3.
		pubAck, err = js.Publish("foo", nil)
		require_NoError(t, err)
		require_Equal(t, pubAck.Sequence, 2)
	}

	t.Run("R1", func(t *testing.T) { test(t, 1) })
	t.Run("R3", func(t *testing.T) { test(t, 3) })
}

func TestJetStreamScheduledMirrorOrSource(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	_, err := jsStreamCreate(t, nc, &StreamConfig{
		Name:              "TEST",
		Storage:           FileStorage,
		Mirror:            &StreamSource{Name: "M"},
		AllowMsgSchedules: true,
	})
	require_Error(t, err, NewJSMirrorWithMsgSchedulesError())

	_, err = jsStreamCreate(t, nc, &StreamConfig{
		Name:              "TEST",
		Storage:           FileStorage,
		Sources:           []*StreamSource{{Name: "S"}},
		AllowMsgSchedules: true,
	})
	require_Error(t, err, NewJSSourceWithMsgSchedulesError())
}

func TestJetStreamOfflineStreamAndConsumerAfterDowngrade(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()
	port := s.getOpts().Port
	sd := s.JetStreamConfig().StoreDir

	_, err := s.globalAccount().addStream(&StreamConfig{
		Name:     "DowngradeStreamTest",
		Storage:  FileStorage,
		Replicas: 1,
		Metadata: map[string]string{"_nats.req.level": strconv.Itoa(math.MaxInt)},
	})
	require_NoError(t, err)

	s.Shutdown()
	s = RunJetStreamServerOnPort(port, sd)
	defer s.Shutdown()

	nc := clientConnectToServer(t, s)
	defer nc.Close()

	offlineReason := fmt.Sprintf("unsupported - required API level: %d, current API level: %d", math.MaxInt, JSApiLevel)
	msg, err := nc.Request(fmt.Sprintf(JSApiStreamInfoT, "DowngradeStreamTest"), nil, time.Second)
	require_NoError(t, err)
	var si JSApiStreamInfoResponse
	require_NoError(t, json.Unmarshal(msg.Data, &si))
	require_NotNil(t, si.Error)
	require_Error(t, si.Error, NewJSStreamOfflineReasonError(errors.New(offlineReason)))

	var sn JSApiStreamNamesResponse
	msg, err = nc.Request(JSApiStreams, nil, time.Second)
	require_NoError(t, err)
	require_NoError(t, json.Unmarshal(msg.Data, &sn))
	require_Len(t, len(sn.Streams), 1)
	require_Equal(t, sn.Streams[0], "DowngradeStreamTest")

	var sl JSApiStreamListResponse
	msg, err = nc.Request(JSApiStreamList, nil, time.Second)
	require_NoError(t, err)
	require_NoError(t, json.Unmarshal(msg.Data, &sl))
	require_Len(t, len(sl.Streams), 0)
	require_Len(t, len(sl.Missing), 1)
	require_Equal(t, sl.Missing[0], "DowngradeStreamTest")
	require_Len(t, len(sl.Offline), 1)
	require_Equal(t, sl.Offline["DowngradeStreamTest"], offlineReason)

	mset, err := s.globalAccount().lookupStream("DowngradeStreamTest")
	require_NoError(t, err)
	require_True(t, mset.closed.Load())
	require_Equal(t, mset.offlineReason, offlineReason)
	require_NoError(t, mset.delete())

	s.Shutdown()
	s = RunJetStreamServerOnPort(port, sd)
	defer s.Shutdown()

	_, err = s.globalAccount().addStream(&StreamConfig{
		Name:     "DowngradeConsumerTest",
		Storage:  FileStorage,
		Replicas: 1,
	})
	require_NoError(t, err)
	mset, err = s.globalAccount().lookupStream("DowngradeConsumerTest")
	require_NoError(t, err)
	_, err = mset.addConsumer(&ConsumerConfig{
		Name:     "DowngradeConsumerTest",
		Metadata: map[string]string{"_nats.req.level": strconv.Itoa(math.MaxInt)},
	})
	require_NoError(t, err)

	s.Shutdown()
	s = RunJetStreamServerOnPort(port, sd)
	defer s.Shutdown()

	mset, err = s.globalAccount().lookupStream("DowngradeConsumerTest")
	require_NoError(t, err)
	require_True(t, mset.closed.Load())
	require_Equal(t, mset.offlineReason, "stopped - unsupported consumer \"DowngradeConsumerTest\"")

	obs := mset.getPublicConsumers()
	require_Len(t, len(obs), 1)
	require_True(t, obs[0].isClosed())
	require_Equal(t, obs[0].offlineReason, offlineReason)

	msg, err = nc.Request(fmt.Sprintf(JSApiConsumerInfoT, "DowngradeConsumerTest", "DowngradeConsumerTest"), nil, time.Second)
	require_NoError(t, err)
	var ci JSApiConsumerInfoResponse
	require_NoError(t, json.Unmarshal(msg.Data, &ci))
	require_NotNil(t, ci.Error)
	require_Error(t, ci.Error, NewJSConsumerOfflineReasonError(errors.New(offlineReason)))

	var cn JSApiConsumerNamesResponse
	msg, err = nc.Request(fmt.Sprintf(JSApiConsumersT, "DowngradeConsumerTest"), nil, time.Second)
	require_NoError(t, err)
	require_NoError(t, json.Unmarshal(msg.Data, &cn))
	require_Len(t, len(cn.Consumers), 1)
	require_Equal(t, cn.Consumers[0], "DowngradeConsumerTest")

	var cl JSApiConsumerListResponse
	msg, err = nc.Request(fmt.Sprintf(JSApiConsumerListT, "DowngradeConsumerTest"), nil, time.Second)
	require_NoError(t, err)
	require_NoError(t, json.Unmarshal(msg.Data, &cl))
	require_Len(t, len(cl.Consumers), 0)
	require_Len(t, len(cl.Missing), 1)
	require_Equal(t, cl.Missing[0], "DowngradeConsumerTest")
	require_Len(t, len(cl.Offline), 1)
	require_Equal(t, cl.Offline["DowngradeConsumerTest"], offlineReason)
}

func TestJetStreamPersistModeAsync(t *testing.T) {
	s := RunBasicJetStreamServer(t)
	defer s.Shutdown()

	nc, js := jsClientConnect(t, s)
	defer nc.Close()

	cfg := &StreamConfig{
		Name:        "TEST",
		Subjects:    []string{"foo"},
		Storage:     MemoryStorage,
		PersistMode: AsyncPersistMode,
	}
	_, err := jsStreamCreate(t, nc, cfg)
	require_Error(t, err, NewJSStreamInvalidConfigError(fmt.Errorf("async persist mode is only supported on file storage")))

	cfg.Storage = FileStorage
	si, err := jsStreamCreate(t, nc, cfg)
	require_NoError(t, err)
	require_Equal(t, si.PersistMode, AsyncPersistMode)

	pubAck, err := js.Publish("foo", nil)
	require_NoError(t, err)
	require_Equal(t, pubAck.Sequence, 1)

	mset, err := s.globalAccount().lookupStream("TEST")
	require_NoError(t, err)
	fs := mset.store.(*fileStore)
	fs.mu.RLock()
	asyncFlush := fs.fcfg.AsyncFlush
	fs.mu.RUnlock()
	require_True(t, asyncFlush)

	cfg.PersistMode = DefaultPersistMode
	_, err = jsStreamUpdate(t, nc, cfg)
	require_Error(t, err, NewJSStreamInvalidConfigError(fmt.Errorf("stream configuration update can not change persist mode")))
}

func TestJetStreamRemoveTTLOnRemoveMsg(t *testing.T) {
	for _, storageType := range []nats.StorageType{nats.FileStorage, nats.MemoryStorage} {
		t.Run(storageType.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := js.AddStream(&nats.StreamConfig{
				Name:        "TEST",
				Subjects:    []string{"foo"},
				Storage:     storageType,
				AllowMsgTTL: true,
			})
			require_NoError(t, err)

			_, err = js.Publish("foo", nil, nats.MsgTTL(time.Hour))
			require_NoError(t, err)

			mset, err := s.globalAccount().lookupStream("TEST")
			require_NoError(t, err)

			validateTTLCount := func(count uint64) {
				store := mset.Store()
				switch storageType {
				case nats.FileStorage:
					fs := store.(*fileStore)
					fs.mu.RLock()
					defer fs.mu.RUnlock()
					require_Equal(t, fs.ttls.Count(), count)
				case nats.MemoryStorage:
					ms := store.(*memStore)
					ms.mu.RLock()
					defer ms.mu.RUnlock()
					require_Equal(t, ms.ttls.Count(), count)
				}
			}
			validateTTLCount(1)

			require_NoError(t, js.DeleteMsg("TEST", 1))
			validateTTLCount(0)
		})
	}
}

func TestJetStreamMessageTTLNotExpiring(t *testing.T) {
	for _, storageType := range []nats.StorageType{nats.FileStorage, nats.MemoryStorage} {
		t.Run(storageType.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := js.AddStream(&nats.StreamConfig{
				Name:        "TEST",
				Subjects:    []string{"foo"},
				Storage:     storageType,
				AllowMsgTTL: true,
			})
			require_NoError(t, err)

			// Triggers the expiry timer once, and needs to be reset to trigger earlier.
			_, err = js.Publish("foo", nil, nats.MsgTTL(time.Hour))
			require_NoError(t, err)

			mset, err := s.globalAccount().lookupStream("TEST")
			require_NoError(t, err)

			// Storing messages with a TTL would continuously reset the timer.
			var wg sync.WaitGroup
			wg.Add(1)
			defer wg.Wait()
			ctx, cancel := context.WithCancel(context.Background())
			defer cancel()
			go func() {
				defer wg.Done()
				for {
					select {
					case <-ctx.Done():
						return
					case <-time.After(100 * time.Millisecond):
						ttl := time.Hour.Nanoseconds()
						store := mset.Store()
						store.StoreMsg("foo", nil, nil, ttl)
					}
				}
			}()

			// The message should be expired timely.
			pubAck, err := js.Publish("foo", nil, nats.MsgTTL(time.Second))
			require_NoError(t, err)
			checkFor(t, 3*time.Second, 100*time.Millisecond, func() error {
				_, err = js.GetMsg("TEST", pubAck.Sequence)
				if err == nil {
					return fmt.Errorf("message not removed yet")
				}
				if !errors.Is(err, nats.ErrMsgNotFound) {
					return err
				}
				return nil
			})
		})
	}
}

func TestJetStreamScheduledMessageNotTriggering(t *testing.T) {
	for _, storageType := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storageType.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := jsStreamCreate(t, nc, &StreamConfig{
				Name:              "TEST",
				Subjects:          []string{"foo.>"},
				Storage:           storageType,
				AllowMsgSchedules: true,
			})
			require_NoError(t, err)

			delay := func(d time.Duration) string {
				return fmt.Sprintf("@at %s", time.Now().Add(d).Format(time.RFC3339Nano))
			}

			// Triggers the schedule timer once, and needs to be reset to trigger earlier.
			m := nats.NewMsg("foo.schedule.first")
			m.Header.Set("Nats-Schedule", delay(time.Hour))
			m.Header.Set("Nats-Schedule-Target", "foo.msg")
			_, err = js.PublishMsg(m)
			require_NoError(t, err)

			// Storing messages with a schedule would continuously reset the timer.
			var wg sync.WaitGroup
			wg.Add(1)
			defer wg.Wait()
			ctx, cancel := context.WithCancel(context.Background())
			defer cancel()
			go func() {
				defer wg.Done()
				var i int
				for {
					select {
					case <-ctx.Done():
						return
					case <-time.After(100 * time.Millisecond):
						i++
						ms := nats.NewMsg(fmt.Sprintf("foo.schedule.%d", i))
						ms.Header.Set("Nats-Schedule", delay(time.Hour))
						ms.Header.Set("Nats-Schedule-Target", "foo.msg")
						js.PublishMsg(ms)
					}
				}
			}()

			// The message should be scheduled timely.
			m = nats.NewMsg("foo.schedule.validate")
			m.Header.Set("Nats-Schedule", delay(time.Second))
			m.Header.Set("Nats-Schedule-Target", "foo.msg")
			_, err = js.PublishMsg(m)
			require_NoError(t, err)
			pubAck, err := js.PublishMsg(m)
			require_NoError(t, err)
			checkFor(t, 3*time.Second, 100*time.Millisecond, func() error {
				_, err = js.GetMsg("TEST", pubAck.Sequence)
				if err == nil {
					return fmt.Errorf("message not removed yet")
				}
				if !errors.Is(err, nats.ErrMsgNotFound) {
					return err
				}
				return nil
			})
		})
	}
}

func TestJetStreamScheduledMessageNotDeactivated(t *testing.T) {
	for _, storageType := range []StorageType{FileStorage, MemoryStorage} {
		t.Run(storageType.String(), func(t *testing.T) {
			s := RunBasicJetStreamServer(t)
			defer s.Shutdown()

			nc, js := jsClientConnect(t, s)
			defer nc.Close()

			_, err := jsStreamCreate(t, nc, &StreamConfig{
				Name:              "TEST",
				Subjects:          []string{"foo.>"},
				Storage:           storageType,
				AllowMsgSchedules: true,
			})
			require_NoError(t, err)

			delay := func(d time.Duration) string {
				return fmt.Sprintf("@at %s", time.Now().Add(d).Format(time.RFC3339Nano))
			}

			// Message should be scheduled.
			m := nats.NewMsg("foo.schedule")
			m.Header.Set("Nats-Schedule", delay(time.Second))
			m.Header.Set("Nats-Schedule-Target", "foo.msg1")
			_, err = js.PublishMsg(m)
			require_NoError(t, err)
			checkFor(t, 2*time.Second, 100*time.Millisecond, func() error {
				_, err = js.GetLastMsg("TEST", "foo.msg1")
				if err != nil {
					return err
				}
				return nil
			})

			// A message with a schedule is published.
			m = nats.NewMsg("foo.schedule")
			m.Header.Set("Nats-Schedule", delay(time.Second))
			m.Header.Set("Nats-Schedule-Target", "foo.msg2")
			_, err = js.PublishMsg(m)
			require_NoError(t, err)

			// But, a publish that is not a schedule should deactivate it.
			_, err = js.Publish("foo.schedule", nil)
			require_NoError(t, err)

			// Wait for some time, and confirm the schedule wasn't triggered.
			time.Sleep(1500 * time.Millisecond)
			_, err = js.GetLastMsg("TEST", "foo.msg2")
			require_Error(t, err, nats.ErrMsgNotFound)
		})
	}
}
