github.com/altipla-consulting/ravendb-go-client@v0.1.3/tests/subscriptions_basic_test.go (about)

     1  package tests
     2  
     3  import (
     4  	"errors"
     5  	"reflect"
     6  	"sync/atomic"
     7  	"testing"
     8  	"time"
     9  
    10  	ravendb "github.com/altipla-consulting/ravendb-go-client"
    11  	"github.com/stretchr/testify/assert"
    12  )
    13  
    14  const (
    15  	_reasonableWaitTime = time.Second * 5 // TODO: is it 60 seconds in Java?
    16  )
    17  
    18  // returns true if timed out
    19  func chanWaitTimedOut(ch chan bool, timeout time.Duration) bool {
    20  	select {
    21  	case <-ch:
    22  		return false
    23  	case <-time.After(timeout):
    24  		return true
    25  	}
    26  }
    27  
    28  // returns false if timed out
    29  func getNextUser(docs chan *User, timeout time.Duration) (*User, bool) {
    30  	if timeout == 0 {
    31  		timeout = _reasonableWaitTime
    32  	}
    33  	select {
    34  	case u := <-docs:
    35  		return u, true
    36  	case <-time.After(timeout):
    37  		return nil, false
    38  	}
    39  }
    40  
    41  func subscriptionsBasic_canDeleteSubscription(t *testing.T, driver *RavenTestDriver) {
    42  	var err error
    43  	store := driver.getDocumentStoreMust(t)
    44  	defer store.Close()
    45  
    46  	id1, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), nil, "")
    47  	assert.NoError(t, err)
    48  	id2, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), nil, "")
    49  	assert.NoError(t, err)
    50  
    51  	subscriptions, err := store.Subscriptions().GetSubscriptions(0, 5, "")
    52  	assert.NoError(t, err)
    53  	assert.Equal(t, len(subscriptions), 2)
    54  
    55  	// test getSubscriptionState as well
    56  	subscriptionState, err := store.Subscriptions().GetSubscriptionState(id1, "")
    57  	assert.NoError(t, err)
    58  	cv := subscriptionState.ChangeVectorForNextBatchStartingPoint
    59  	assert.Nil(t, cv)
    60  
    61  	err = store.Subscriptions().Delete(id1, "")
    62  	assert.NoError(t, err)
    63  	err = store.Subscriptions().Delete(id2, "")
    64  	assert.NoError(t, err)
    65  
    66  	subscriptions, err = store.Subscriptions().GetSubscriptions(0, 5, "")
    67  	assert.NoError(t, err)
    68  	assert.Equal(t, len(subscriptions), 0)
    69  }
    70  
    71  func subscriptionsBasic_shouldThrowWhenOpeningNoExistingSubscription(t *testing.T, driver *RavenTestDriver) {
    72  	store := driver.getDocumentStoreMust(t)
    73  	defer store.Close()
    74  
    75  	clazz := reflect.TypeOf(&map[string]interface{}{})
    76  	opts := ravendb.NewSubscriptionWorkerOptions("1")
    77  
    78  	subscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, opts, "")
    79  	assert.NoError(t, err)
    80  
    81  	results := make(chan *ravendb.SubscriptionBatch, 16)
    82  	cb := func(batch *ravendb.SubscriptionBatch) error {
    83  		results <- batch
    84  		return nil
    85  	}
    86  	err = subscription.Run(cb)
    87  
    88  	assert.NoError(t, err)
    89  	err = subscription.WaitUntilFinished(0)
    90  	assert.NotNil(t, err)
    91  	_, ok := err.(*ravendb.SubscriptionDoesNotExistError)
    92  	assert.True(t, ok)
    93  	assert.Equal(t, err, subscription.Err())
    94  
    95  	err = subscription.Close()
    96  	assert.NoError(t, err)
    97  }
    98  
    99  func subscriptionsBasic_shouldThrowOnAttemptToOpenAlreadyOpenedSubscription(t *testing.T, driver *RavenTestDriver) {
   100  	store := driver.getDocumentStoreMust(t)
   101  	defer store.Close()
   102  
   103  	id, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), nil, "")
   104  	assert.NoError(t, err)
   105  
   106  	{
   107  		clazz := reflect.TypeOf(map[string]interface{}{})
   108  		opts := ravendb.NewSubscriptionWorkerOptions(id)
   109  		subscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, opts, "")
   110  		assert.NoError(t, err)
   111  
   112  		{
   113  			session, err := store.OpenSession("")
   114  			assert.NoError(t, err)
   115  			err = session.Store(&User{})
   116  			assert.NoError(t, err)
   117  			err = session.SaveChanges()
   118  			assert.NoError(t, err)
   119  
   120  			session.Close()
   121  		}
   122  
   123  		results := make(chan *ravendb.SubscriptionBatch, 16)
   124  		cb := func(batch *ravendb.SubscriptionBatch) error {
   125  			results <- batch
   126  			return nil
   127  		}
   128  		err = subscription.Run(cb)
   129  		assert.NoError(t, err)
   130  
   131  		select {
   132  		case <-results:
   133  		// no-op, got the result
   134  		case <-time.After(_reasonableWaitTime):
   135  			// no-op, timeout waiting for the result
   136  		}
   137  
   138  		options2 := ravendb.NewSubscriptionWorkerOptions(id)
   139  		options2.Strategy = ravendb.SubscriptionOpeningStrategyOpenIfFree
   140  
   141  		{
   142  			secondSubscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, options2, "")
   143  			assert.NoError(t, err)
   144  			cb := func(batch *ravendb.SubscriptionBatch) error {
   145  				return nil
   146  			}
   147  			err = secondSubscription.Run(cb)
   148  			assert.NoError(t, err)
   149  			err = secondSubscription.WaitUntilFinished(0)
   150  			_, ok := err.(*ravendb.SubscriptionInUseError)
   151  			assert.True(t, ok)
   152  
   153  			err = secondSubscription.Close()
   154  			assert.NoError(t, err)
   155  		}
   156  
   157  		err = subscription.Close()
   158  		assert.NoError(t, err)
   159  	}
   160  
   161  }
   162  
   163  func subscriptionsBasic_shouldStreamAllDocumentsAfterSubscriptionCreation(t *testing.T, driver *RavenTestDriver) {
   164  	var err error
   165  	store := driver.getDocumentStoreMust(t)
   166  	defer store.Close()
   167  
   168  	var users []*User
   169  	{
   170  		session := openSessionMust(t, store)
   171  
   172  		user1 := &User{
   173  			Age: 31,
   174  		}
   175  		err = session.StoreWithID(user1, "users/1")
   176  		assert.NoError(t, err)
   177  		users = append(users, user1)
   178  
   179  		user2 := &User{
   180  			Age: 27,
   181  		}
   182  		err = session.StoreWithID(user2, "users/12")
   183  		assert.NoError(t, err)
   184  		users = append(users, user2)
   185  
   186  		user3 := &User{
   187  			Age: 25,
   188  		}
   189  		err = session.StoreWithID(user3, "users/3")
   190  		assert.NoError(t, err)
   191  		users = append(users, user3)
   192  
   193  		err = session.SaveChanges()
   194  		assert.NoError(t, err)
   195  
   196  		session.Close()
   197  	}
   198  
   199  	id, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), nil, "")
   200  	assert.NoError(t, err)
   201  
   202  	{
   203  		opts := ravendb.NewSubscriptionWorkerOptions(id)
   204  		clazz := reflect.TypeOf(&User{})
   205  		subscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, opts, "")
   206  		assert.NoError(t, err)
   207  
   208  		results := make(chan *ravendb.SubscriptionBatch, 16)
   209  		cb := func(batch *ravendb.SubscriptionBatch) error {
   210  			results <- batch
   211  			return nil
   212  		}
   213  		err = subscription.Run(cb)
   214  		assert.NoError(t, err)
   215  
   216  		chDone := make(chan bool, 1)
   217  		go func() {
   218  			for batch := range results {
   219  				for i, item := range batch.Items {
   220  					expUser := users[i]
   221  					assert.Equal(t, item.ID, expUser.ID)
   222  					var u *User
   223  					err := item.GetResult(&u)
   224  					assert.NoError(t, err)
   225  					assert.Equal(t, u.Age, expUser.Age)
   226  				}
   227  				chDone <- true
   228  			}
   229  		}()
   230  		select {
   231  		case <-chDone:
   232  		// no-op, got the first batch
   233  		case <-time.After(_reasonableWaitTime):
   234  			assert.Fail(t, "timed out waiting for batch")
   235  		}
   236  
   237  		err = subscription.Close()
   238  		assert.NoError(t, err)
   239  	}
   240  }
   241  
   242  func subscriptionsBasic_shouldSendAllNewAndModifiedDocs(t *testing.T, driver *RavenTestDriver) {
   243  	var err error
   244  	store := driver.getDocumentStoreMust(t)
   245  	defer store.Close()
   246  
   247  	id, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), nil, "")
   248  	assert.NoError(t, err)
   249  
   250  	{
   251  		opts := ravendb.NewSubscriptionWorkerOptions(id)
   252  		clazz := reflect.TypeOf(map[string]interface{}{})
   253  		subscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, opts, "")
   254  		assert.NoError(t, err)
   255  
   256  		{
   257  			session := openSessionMust(t, store)
   258  
   259  			user := &User{}
   260  			user.setName("James")
   261  			err = session.StoreWithID(user, "users/1")
   262  			assert.NoError(t, err)
   263  
   264  			err = session.SaveChanges()
   265  			assert.NoError(t, err)
   266  
   267  			session.Close()
   268  		}
   269  
   270  		results := make(chan *ravendb.SubscriptionBatch, 16)
   271  		cb := func(batch *ravendb.SubscriptionBatch) error {
   272  			results <- batch
   273  			return nil
   274  		}
   275  		err = subscription.Run(cb)
   276  		assert.NoError(t, err)
   277  		go func() {
   278  			expNames := []string{"James", "Adam", "David"}
   279  			var n int
   280  			for batch := range results {
   281  				for _, item := range batch.Items {
   282  					var m map[string]interface{}
   283  					err := item.GetResult(&m)
   284  					assert.NoError(t, err)
   285  					name := m["name"].(string)
   286  					assert.Equal(t, name, expNames[n])
   287  					n++
   288  				}
   289  			}
   290  		}()
   291  
   292  		{
   293  			session := openSessionMust(t, store)
   294  
   295  			user := &User{}
   296  			user.setName("Adam")
   297  			err = session.StoreWithID(user, "users/12")
   298  			assert.NoError(t, err)
   299  
   300  			err = session.SaveChanges()
   301  			assert.NoError(t, err)
   302  
   303  			session.Close()
   304  		}
   305  
   306  		//Thread.sleep(15000); // test with sleep - let few heartbeats come to us - commented out for CI
   307  
   308  		{
   309  			session := openSessionMust(t, store)
   310  
   311  			user := &User{}
   312  			user.setName("David")
   313  			err = session.StoreWithID(user, "users/1")
   314  			assert.NoError(t, err)
   315  
   316  			err = session.SaveChanges()
   317  			assert.NoError(t, err)
   318  
   319  			session.Close()
   320  		}
   321  
   322  		err = subscription.Close()
   323  		assert.NoError(t, err)
   324  	}
   325  }
   326  
   327  func subscriptionsBasic_shouldRespectMaxDocCountInBatch(t *testing.T, driver *RavenTestDriver) {
   328  	var err error
   329  	store := driver.getDocumentStoreMust(t)
   330  	defer store.Close()
   331  
   332  	{
   333  		session := openSessionMust(t, store)
   334  
   335  		for i := 0; i < 100; i++ {
   336  			err = session.Store(&Company{})
   337  			assert.NoError(t, err)
   338  		}
   339  
   340  		err = session.SaveChanges()
   341  		assert.NoError(t, err)
   342  
   343  		session.Close()
   344  	}
   345  
   346  	clazz := reflect.TypeOf(&Company{})
   347  	id, err := store.Subscriptions().CreateForType(clazz, nil, "")
   348  	assert.NoError(t, err)
   349  
   350  	options := ravendb.NewSubscriptionWorkerOptions(id)
   351  	options.MaxDocsPerBatch = 25
   352  
   353  	{
   354  		clazz = reflect.TypeOf(map[string]interface{}{})
   355  		subscriptionWorker, err := store.Subscriptions().GetSubscriptionWorker(clazz, options, "")
   356  		assert.NoError(t, err)
   357  
   358  		results := make(chan *ravendb.SubscriptionBatch, 16)
   359  		cb := func(batch *ravendb.SubscriptionBatch) error {
   360  			results <- batch
   361  			return nil
   362  		}
   363  		err = subscriptionWorker.Run(cb)
   364  		assert.NoError(t, err)
   365  
   366  		var totalItems int
   367  		for totalItems < 100 {
   368  			select {
   369  			case batch := <-results:
   370  				n := len(batch.Items)
   371  				assert.True(t, n <= 25)
   372  				totalItems += n
   373  			case <-time.After(_reasonableWaitTime):
   374  				assert.Fail(t,  "timed out waiting for a batch")
   375  				totalItems = 100
   376  			}
   377  		}
   378  		_ = subscriptionWorker.Close()
   379  	}
   380  }
   381  
   382  func subscriptionsBasic_shouldRespectCollectionCriteria(t *testing.T, driver *RavenTestDriver) {
   383  	var err error
   384  	store := driver.getDocumentStoreMust(t)
   385  	defer store.Close()
   386  
   387  	{
   388  		session := openSessionMust(t, store)
   389  
   390  		for i := 0; i < 100; i++ {
   391  			err = session.Store(&Company{})
   392  			assert.NoError(t, err)
   393  			err = session.Store(&User{})
   394  			assert.NoError(t, err)
   395  		}
   396  
   397  		err = session.SaveChanges()
   398  		assert.NoError(t, err)
   399  
   400  		session.Close()
   401  	}
   402  
   403  	clazz := reflect.TypeOf(&User{})
   404  	id, err := store.Subscriptions().CreateForType(clazz, nil, "")
   405  	assert.NoError(t, err)
   406  
   407  	options := ravendb.NewSubscriptionWorkerOptions(id)
   408  	options.MaxDocsPerBatch = 31
   409  
   410  	{
   411  		clazz = reflect.TypeOf(map[string]interface{}{})
   412  		subscriptionWorker, err := store.Subscriptions().GetSubscriptionWorker(clazz, options, "")
   413  		assert.NoError(t, err)
   414  
   415  		results := make(chan *ravendb.SubscriptionBatch, 16)
   416  		cb := func(batch *ravendb.SubscriptionBatch) error {
   417  			results <- batch
   418  			return nil
   419  		}
   420  		err = subscriptionWorker.Run(cb)
   421  		assert.NoError(t, err)
   422  
   423  		var totalItems int
   424  		for totalItems < 100 {
   425  			select {
   426  			case batch := <-results:
   427  				n := len(batch.Items)
   428  				assert.True(t, n <= 31)
   429  				totalItems += n
   430  			case <-time.After(_reasonableWaitTime):
   431  				assert.Fail(t, "timed out waiting for batch")
   432  				totalItems = 100
   433  			}
   434  
   435  		}
   436  
   437  		_ = subscriptionWorker.Close()
   438  	}
   439  }
   440  
   441  func subscriptionsBasic_willAcknowledgeEmptyBatches(t *testing.T, driver *RavenTestDriver) {
   442  	var err error
   443  	store := driver.getDocumentStoreMust(t)
   444  	defer store.Close()
   445  
   446  	subscriptionDocuments, err := store.Subscriptions().GetSubscriptions(0, 10, "")
   447  	assert.NoError(t, err)
   448  	assert.Equal(t, len(subscriptionDocuments), 0)
   449  
   450  	opts := &ravendb.SubscriptionCreationOptions{}
   451  	clazz := reflect.TypeOf(&User{})
   452  	allId, err := store.Subscriptions().CreateForType(clazz, opts, "")
   453  	assert.NoError(t, err)
   454  
   455  	{
   456  		clazz = reflect.TypeOf(map[string]interface{}{})
   457  		opts := ravendb.NewSubscriptionWorkerOptions(allId)
   458  		allSubscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, opts, "")
   459  		assert.NoError(t, err)
   460  
   461  		var allCounter int32
   462  		allSemaphore := make(chan bool)
   463  
   464  		filteredOptions := &ravendb.SubscriptionCreationOptions{
   465  			Query: "from Users where age < 0",
   466  		}
   467  		filteredUsersId, err := store.Subscriptions().Create(filteredOptions, "")
   468  		assert.NoError(t, err)
   469  
   470  		{
   471  			clazz = reflect.TypeOf(map[string]interface{}{})
   472  			opts := ravendb.NewSubscriptionWorkerOptions(filteredUsersId)
   473  			filteredUsersSubscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, opts, "")
   474  			assert.NoError(t, err)
   475  
   476  			usersDocsSemaphore := make(chan bool)
   477  
   478  			{
   479  				session := openSessionMust(t, store)
   480  
   481  				for i := 0; i < 500; i++ {
   482  					err = session.StoreWithID(&User{}, "another/")
   483  					assert.NoError(t, err)
   484  				}
   485  
   486  				err = session.SaveChanges()
   487  				assert.NoError(t, err)
   488  
   489  				session.Close()
   490  			}
   491  
   492  			results := make(chan *ravendb.SubscriptionBatch, 16)
   493  			cb := func(batch *ravendb.SubscriptionBatch) error {
   494  				results <- batch
   495  				return nil
   496  			}
   497  			err = allSubscription.Run(cb)
   498  			assert.NoError(t, err)
   499  
   500  			go func() {
   501  				for batch := range results {
   502  					n := len(batch.Items)
   503  					total := atomic.AddInt32(&allCounter, int32(n))
   504  					if total >= 100 {
   505  						allSemaphore <- true
   506  					}
   507  				}
   508  			}()
   509  
   510  			results2 := make(chan *ravendb.SubscriptionBatch, 16)
   511  			cb2 := func(batch *ravendb.SubscriptionBatch) error {
   512  				results <- batch
   513  				return nil
   514  			}
   515  			err = filteredUsersSubscription.Run(cb2)
   516  			assert.NoError(t, err)
   517  
   518  			// TODO: more go-ish waiting using select on 2 channels
   519  			go func() {
   520  				for range results2 {
   521  					usersDocsSemaphore <- true
   522  				}
   523  			}()
   524  
   525  			timedOut := chanWaitTimedOut(allSemaphore, _reasonableWaitTime)
   526  			assert.False(t, timedOut)
   527  			timedOut = chanWaitTimedOut(usersDocsSemaphore, time.Millisecond*50)
   528  			assert.True(t, timedOut)
   529  		}
   530  
   531  		_ = allSubscription.Close()
   532  	}
   533  }
   534  
   535  func subscriptionsBasic_canReleaseSubscription(t *testing.T, driver *RavenTestDriver) {
   536  	var err error
   537  	store := driver.getDocumentStoreMust(t)
   538  	defer store.Close()
   539  
   540  	var subscriptionWorker *ravendb.SubscriptionWorker
   541  	var throwingSubscriptionWorker *ravendb.SubscriptionWorker
   542  	var notThrowingSubscriptionWorker *ravendb.SubscriptionWorker
   543  
   544  	defer func() {
   545  		if subscriptionWorker != nil {
   546  			_ = subscriptionWorker.Close()
   547  		}
   548  		if throwingSubscriptionWorker != nil {
   549  			_ = throwingSubscriptionWorker.Close()
   550  		}
   551  		if notThrowingSubscriptionWorker != nil {
   552  			_ = notThrowingSubscriptionWorker.Close()
   553  		}
   554  	}()
   555  
   556  	opts := &ravendb.SubscriptionCreationOptions{}
   557  	clazz := reflect.TypeOf(&User{})
   558  	id, err := store.Subscriptions().CreateForType(clazz, opts, "")
   559  	assert.NoError(t, err)
   560  
   561  	options1 := ravendb.NewSubscriptionWorkerOptions(id)
   562  	options1.Strategy = ravendb.SubscriptionOpeningStrategyOpenIfFree
   563  	clazz = reflect.TypeOf(map[string]interface{}{})
   564  	subscriptionWorker, err = store.Subscriptions().GetSubscriptionWorker(clazz, options1, "")
   565  	assert.NoError(t, err)
   566  
   567  	putUserDoc(t, store)
   568  
   569  	results := make(chan *ravendb.SubscriptionBatch, 16)
   570  	cb := func(batch *ravendb.SubscriptionBatch) error {
   571  		results <- batch
   572  		return nil
   573  	}
   574  	err = subscriptionWorker.Run(cb)
   575  	assert.NoError(t, err)
   576  	select {
   577  	case <-results:
   578  	// no-op, got a result
   579  	case <-time.After(_reasonableWaitTime):
   580  		assert.Fail(t, "timed out waiting for batch")
   581  	}
   582  
   583  	options2 := ravendb.NewSubscriptionWorkerOptions(id)
   584  	options2.Strategy = ravendb.SubscriptionOpeningStrategyOpenIfFree
   585  	throwingSubscriptionWorker, err = store.Subscriptions().GetSubscriptionWorker(clazz, options2, "")
   586  	assert.NoError(t, err)
   587  
   588  	cbNil := func(batch *ravendb.SubscriptionBatch) error {
   589  		return nil
   590  	}
   591  	err = throwingSubscriptionWorker.Run(cbNil)
   592  	err = throwingSubscriptionWorker.WaitUntilFinished(0)
   593  	_, ok := err.(*ravendb.SubscriptionInUseError)
   594  	assert.True(t, ok)
   595  
   596  	err = store.Subscriptions().DropConnection(id, "")
   597  	assert.NoError(t, err)
   598  
   599  	wopts := ravendb.NewSubscriptionWorkerOptions(id)
   600  	notThrowingSubscriptionWorker, err = store.Subscriptions().GetSubscriptionWorker(clazz, wopts, "")
   601  
   602  	results = make(chan *ravendb.SubscriptionBatch, 16)
   603  	err = notThrowingSubscriptionWorker.Run(cb)
   604  	assert.NoError(t, err)
   605  	putUserDoc(t, store)
   606  
   607  	select {
   608  	case <-results:
   609  	// no-op, got a result
   610  	case <-time.After(_reasonableWaitTime):
   611  		assert.Fail(t, "timed out waiting for batch")
   612  	}
   613  }
   614  
   615  func putUserDoc(t *testing.T, store *ravendb.DocumentStore) {
   616  	session, err := store.OpenSession("")
   617  	assert.NoError(t, err)
   618  	defer session.Close()
   619  
   620  	err = session.Store(&User{})
   621  	assert.NoError(t, err)
   622  	err = session.SaveChanges()
   623  	assert.NoError(t, err)
   624  }
   625  
   626  func subscriptionsBasic_shouldPullDocumentsAfterBulkInsert(t *testing.T, driver *RavenTestDriver) {
   627  	var err error
   628  	store := driver.getDocumentStoreMust(t)
   629  	defer store.Close()
   630  
   631  	opts := &ravendb.SubscriptionCreationOptions{}
   632  	id, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), opts, "")
   633  	assert.NoError(t, err)
   634  
   635  	{
   636  		clazz := reflect.TypeOf(&User{})
   637  		wopts := ravendb.NewSubscriptionWorkerOptions(id)
   638  		subscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, wopts, "")
   639  		{
   640  			bulk := store.BulkInsert("")
   641  			_, err = bulk.Store(&User{}, nil)
   642  			assert.NoError(t, err)
   643  			_, err = bulk.Store(&User{}, nil)
   644  			assert.NoError(t, err)
   645  			_, err = bulk.Store(&User{}, nil)
   646  			assert.NoError(t, err)
   647  			err = bulk.Close()
   648  			assert.NoError(t, err)
   649  		}
   650  
   651  		results := make(chan *ravendb.SubscriptionBatch, 16)
   652  		cb := func(batch *ravendb.SubscriptionBatch) error {
   653  			results <- batch
   654  			return nil
   655  		}
   656  		err = subscription.Run(cb)
   657  
   658  		done := false
   659  		nUsers := 0
   660  		for !done {
   661  			select {
   662  			case batch := <-results:
   663  				for _, item := range batch.Items {
   664  					var u *User
   665  					err := item.GetResult(&u)
   666  					assert.NoError(t, err)
   667  					assert.NotNil(t, u)
   668  					nUsers++
   669  					if nUsers >= 2 {
   670  						done = true
   671  					}
   672  				}
   673  			case <-time.After(_reasonableWaitTime):
   674  				done = true
   675  				assert.Fail(t, "timed out waiting for batch")
   676  			}
   677  		}
   678  
   679  		err = subscription.Close()
   680  		assert.NoError(t, err)
   681  	}
   682  }
   683  
   684  func subscriptionsBasic_shouldStopPullingDocsAndCloseSubscriptionOnSubscriberErrorByDefault(t *testing.T, driver *RavenTestDriver) {
   685  	var err error
   686  	store := driver.getDocumentStoreMust(t)
   687  	defer store.Close()
   688  
   689  	opts := &ravendb.SubscriptionCreationOptions{}
   690  	id, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), opts, "")
   691  	assert.NoError(t, err)
   692  
   693  	{
   694  		clazz := reflect.TypeOf(map[string]interface{}{})
   695  		wopts := ravendb.NewSubscriptionWorkerOptions(id)
   696  		subscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, wopts, "")
   697  
   698  		putUserDoc(t, store)
   699  
   700  		cb := func(batch *ravendb.SubscriptionBatch) error {
   701  			return errors.New("Fake error")
   702  		}
   703  		err = subscription.Run(cb)
   704  		assert.NoError(t, err)
   705  
   706  		err = subscription.WaitUntilFinished(_reasonableWaitTime)
   707  		_, ok := err.(*ravendb.SubscriberErrorError)
   708  		assert.True(t, ok)
   709  		assert.NotNil(t, subscription.Err())
   710  
   711  		res, err := store.Subscriptions().GetSubscriptions(0, 1, "")
   712  		assert.NoError(t, err)
   713  		subscriptionConfig := res[0]
   714  		assert.Nil(t, subscriptionConfig.ChangeVectorForNextBatchStartingPoint)
   715  
   716  		err = subscription.Close()
   717  		assert.NoError(t, err)
   718  	}
   719  }
   720  
   721  func subscriptionsBasic_canSetToIgnoreSubscriberErrors(t *testing.T, driver *RavenTestDriver) {
   722  	var err error
   723  	store := driver.getDocumentStoreMust(t)
   724  	defer store.Close()
   725  
   726  	opts := &ravendb.SubscriptionCreationOptions{}
   727  	id, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), opts, "")
   728  	assert.NoError(t, err)
   729  
   730  	options1 := ravendb.NewSubscriptionWorkerOptions(id)
   731  	options1.IgnoreSubscriberErrors = true
   732  
   733  	{
   734  		clazz := reflect.TypeOf(&User{})
   735  		subscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, options1, "")
   736  		assert.NoError(t, err)
   737  
   738  		putUserDoc(t, store)
   739  		putUserDoc(t, store)
   740  
   741  		results := make(chan *ravendb.SubscriptionBatch, 16)
   742  		cb := func(batch *ravendb.SubscriptionBatch) error {
   743  			results <- batch
   744  			return errors.New("Fake error")
   745  		}
   746  		err = subscription.Run(cb)
   747  		assert.NoError(t, err)
   748  
   749  		done := false
   750  		nUsers := 0
   751  		for !done {
   752  			select {
   753  			case batch := <-results:
   754  				for _, item := range batch.Items {
   755  					var u *User
   756  					err := item.GetResult(&u)
   757  					assert.NoError(t, err)
   758  					assert.NotNil(t, u)
   759  					nUsers++
   760  					if nUsers >= 2 {
   761  						done = true
   762  					}
   763  				}
   764  			case <-time.After(_reasonableWaitTime):
   765  				assert.Fail(t, "timed out waiting for batch")
   766  				done = true
   767  			}
   768  		}
   769  		_ = subscription.Close()
   770  		err = subscription.WaitUntilFinished(0)
   771  		assert.NoError(t, err)
   772  
   773  		// nno error because we asked to ignore errors
   774  		assert.NoError(t, subscription.Err())
   775  
   776  		err = subscription.Close()
   777  		assert.NoError(t, err)
   778  	}
   779  }
   780  
   781  func subscriptionsBasic_ravenDB_3452_ShouldStopPullingDocsIfReleased(t *testing.T, driver *RavenTestDriver) {
   782  	var err error
   783  	store := driver.getDocumentStoreMust(t)
   784  	defer store.Close()
   785  
   786  	opts := &ravendb.SubscriptionCreationOptions{}
   787  	id, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), opts, "")
   788  	assert.NoError(t, err)
   789  
   790  	{
   791  		options1 := ravendb.NewSubscriptionWorkerOptions(id)
   792  		options1.TimeToWaitBeforeConnectionRetry = ravendb.Duration(time.Second)
   793  
   794  		clazz := reflect.TypeOf(&User{})
   795  		subscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, options1, "")
   796  		assert.NoError(t, err)
   797  
   798  		{
   799  			session, err := store.OpenSession("")
   800  			assert.NoError(t, err)
   801  			err = session.StoreWithID(&User{}, "users/1")
   802  			assert.NoError(t, err)
   803  			err = session.StoreWithID(&User{}, "users/2")
   804  			assert.NoError(t, err)
   805  			err = session.SaveChanges()
   806  			assert.NoError(t, err)
   807  
   808  			session.Close()
   809  		}
   810  
   811  		results := make(chan *ravendb.SubscriptionBatch, 16)
   812  		cb := func(batch *ravendb.SubscriptionBatch) error {
   813  			results <- batch
   814  			return nil
   815  		}
   816  		err = subscription.Run(cb)
   817  		assert.NoError(t, err)
   818  
   819  		done := false
   820  		nUsers := 0
   821  		for !done {
   822  			select {
   823  			case batch := <-results:
   824  				for _, item := range batch.Items {
   825  					var u *User
   826  					err := item.GetResult(&u)
   827  					assert.NoError(t, err)
   828  					assert.NotNil(t, u)
   829  					nUsers++
   830  					if nUsers >= 2 {
   831  						done = true
   832  					}
   833  				}
   834  			case <-time.After(_reasonableWaitTime):
   835  				assert.Fail(t, "timed out waiting for batch")
   836  				done = true
   837  			}
   838  		}
   839  
   840  		err = store.Subscriptions().DropConnection(id, "")
   841  		assert.NoError(t, err)
   842  
   843  		// this can exit normally or throw on drop connection
   844  		// depending on exactly where the drop happens
   845  		err = subscription.WaitUntilFinished(_reasonableWaitTime)
   846  		if err != nil {
   847  			_, ok := err.(*ravendb.SubscriptionClosedError)
   848  			assert.True(t, ok)
   849  		}
   850  
   851  		{
   852  			session, err := store.OpenSession("")
   853  			assert.NoError(t, err)
   854  			err = session.StoreWithID(&User{}, "users/3")
   855  			assert.NoError(t, err)
   856  			err = session.StoreWithID(&User{}, "users/4")
   857  			assert.NoError(t, err)
   858  			err = session.SaveChanges()
   859  			assert.NoError(t, err)
   860  
   861  			session.Close()
   862  		}
   863  
   864  		// should get no results since we dropped the connection
   865  
   866  		select {
   867  		case batch := <-results:
   868  			// if we get it, it should be nil because we receive
   869  			// from closed channel
   870  			assert.Nil(t, batch)
   871  		case <-time.After(50 * time.Millisecond):
   872  			// no-op, timeing out is also valid
   873  		}
   874  
   875  		assert.True(t, subscription.IsDone())
   876  
   877  		err = subscription.Close()
   878  		assert.NoError(t, err)
   879  	}
   880  }
   881  
   882  func subscriptionsBasic_ravenDB_3453_ShouldDeserializeTheWholeDocumentsAfterTypedSubscription(t *testing.T, driver *RavenTestDriver) {
   883  	var err error
   884  	store := driver.getDocumentStoreMust(t)
   885  	defer store.Close()
   886  
   887  	opts := &ravendb.SubscriptionCreationOptions{}
   888  	id, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), opts, "")
   889  	assert.NoError(t, err)
   890  
   891  	{
   892  		clazz := reflect.TypeOf(&User{})
   893  		wopts := ravendb.NewSubscriptionWorkerOptions(id)
   894  
   895  		subscription, err := store.Subscriptions().GetSubscriptionWorker(clazz, wopts, "")
   896  		assert.NoError(t, err)
   897  
   898  		var users []*User
   899  		{
   900  			session, err := store.OpenSession("")
   901  			assert.NoError(t, err)
   902  			u := &User{Age: 31}
   903  			err = session.StoreWithID(u, "users/1")
   904  			users = append(users, u)
   905  			assert.NoError(t, err)
   906  			u = &User{Age: 27}
   907  			err = session.StoreWithID(u, "users/12")
   908  			users = append(users, u)
   909  			assert.NoError(t, err)
   910  			u = &User{Age: 25}
   911  			err = session.StoreWithID(u, "users/3")
   912  			users = append(users, u)
   913  			assert.NoError(t, err)
   914  			err = session.SaveChanges()
   915  			assert.NoError(t, err)
   916  
   917  			session.Close()
   918  		}
   919  
   920  		results := make(chan *ravendb.SubscriptionBatch, 16)
   921  		cb := func(batch *ravendb.SubscriptionBatch) error {
   922  			results <- batch
   923  			return nil
   924  		}
   925  		err = subscription.Run(cb)
   926  		assert.NoError(t, err)
   927  
   928  		n := 0
   929  		done := false
   930  		for !done {
   931  			select {
   932  			case batch := <-results:
   933  				for _, item := range batch.Items {
   934  					var u *User
   935  					err := item.GetResult(&u)
   936  					assert.NoError(t, err)
   937  					expU := users[n]
   938  					assert.Equal(t, u.ID, expU.ID)
   939  					assert.Equal(t, u.Age, expU.Age)
   940  					n++
   941  					if n >= len(users) {
   942  						done = true
   943  					}
   944  				}
   945  
   946  			case <-time.After(_reasonableWaitTime):
   947  				done = true
   948  				assert.Fail(t, "timed out waiting for batch")
   949  			}
   950  
   951  			err = subscription.Close()
   952  			assert.NoError(t, err)
   953  		}
   954  	}
   955  }
   956  
   957  func subscriptionsBasic_disposingOneSubscriptionShouldNotAffectOnNotificationsOfOthers(t *testing.T, driver *RavenTestDriver) {
   958  	var err error
   959  	store := driver.getDocumentStoreMust(t)
   960  	defer store.Close()
   961  
   962  	var subscription1 *ravendb.SubscriptionWorker
   963  	var subscription2 *ravendb.SubscriptionWorker
   964  	defer func() {
   965  		if subscription1 != nil {
   966  			_ = subscription1.Close()
   967  		}
   968  		if subscription2 != nil {
   969  			_ = subscription2.Close()
   970  		}
   971  	}()
   972  
   973  	id1, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), nil, "")
   974  	assert.NoError(t, err)
   975  	id2, err := store.Subscriptions().CreateForType(reflect.TypeOf(&User{}), nil, "")
   976  	assert.NoError(t, err)
   977  
   978  	{
   979  		session, err := store.OpenSession("")
   980  		assert.NoError(t, err)
   981  		err = session.StoreWithID(&User{}, "users/1")
   982  		assert.NoError(t, err)
   983  		err = session.StoreWithID(&User{}, "users/2")
   984  		assert.NoError(t, err)
   985  		err = session.SaveChanges()
   986  		assert.NoError(t, err)
   987  
   988  		session.Close()
   989  	}
   990  
   991  	clazz := reflect.TypeOf(&User{})
   992  	opts := ravendb.NewSubscriptionWorkerOptions(id1)
   993  
   994  	subscription1, err = store.Subscriptions().GetSubscriptionWorker(clazz, opts, "")
   995  	assert.NoError(t, err)
   996  
   997  	items1 := make(chan *User, 10)
   998  
   999  	results := make(chan *ravendb.SubscriptionBatch, 16)
  1000  	cb := func(batch *ravendb.SubscriptionBatch) error {
  1001  		results <- batch
  1002  		return nil
  1003  	}
  1004  	err = subscription1.Run(cb)
  1005  	assert.NoError(t, err)
  1006  
  1007  	// TODO: rewrite in a more go-ish way
  1008  	go func() {
  1009  		for batch := range results {
  1010  			for _, item := range batch.Items {
  1011  				var u *User
  1012  				err := item.GetResult(&u)
  1013  				assert.NoError(t, err)
  1014  				items1 <- u
  1015  			}
  1016  		}
  1017  	}()
  1018  
  1019  	opts = ravendb.NewSubscriptionWorkerOptions(id2)
  1020  	subscription2, err = store.Subscriptions().GetSubscriptionWorker(clazz, opts, "")
  1021  	assert.NoError(t, err)
  1022  	items2 := make(chan *User, 10)
  1023  
  1024  	results2 := make(chan *ravendb.SubscriptionBatch, 16)
  1025  	cb2 := func(batch *ravendb.SubscriptionBatch) error {
  1026  		results2 <- batch
  1027  		return nil
  1028  	}
  1029  	err = subscription2.Run(cb2)
  1030  	assert.NoError(t, err)
  1031  	go func() {
  1032  		for batch := range results2 {
  1033  			for _, item := range batch.Items {
  1034  				var u *User
  1035  				err := item.GetResult(&u)
  1036  				assert.NoError(t, err)
  1037  				items2 <- u
  1038  			}
  1039  		}
  1040  	}()
  1041  
  1042  	u, ok := getNextUser(items1, 0)
  1043  	assert.True(t, ok)
  1044  	assert.Equal(t, u.ID, "users/1")
  1045  
  1046  	u, ok = getNextUser(items1, 0)
  1047  	assert.True(t, ok)
  1048  	assert.Equal(t, u.ID, "users/2")
  1049  
  1050  	u, ok = getNextUser(items2, 0)
  1051  	assert.True(t, ok)
  1052  	assert.Equal(t, u.ID, "users/1")
  1053  
  1054  	u, ok = getNextUser(items2, 0)
  1055  	assert.True(t, ok)
  1056  	assert.Equal(t, u.ID, "users/2")
  1057  
  1058  	_ = subscription1.Close()
  1059  	subscription1 = nil
  1060  
  1061  	{
  1062  		session, err := store.OpenSession("")
  1063  		assert.NoError(t, err)
  1064  		err = session.StoreWithID(&User{}, "users/3")
  1065  		assert.NoError(t, err)
  1066  		err = session.StoreWithID(&User{}, "users/4")
  1067  		assert.NoError(t, err)
  1068  		err = session.SaveChanges()
  1069  		assert.NoError(t, err)
  1070  
  1071  		session.Close()
  1072  	}
  1073  
  1074  	u, ok = getNextUser(items2, 0)
  1075  	assert.True(t, ok)
  1076  	assert.Equal(t, u.ID, "users/3")
  1077  
  1078  	u, ok = getNextUser(items2, 0)
  1079  	assert.True(t, ok)
  1080  	assert.Equal(t, u.ID, "users/4")
  1081  }
  1082  
  1083  func TestSubscriptionsBasic(t *testing.T) {
  1084  	driver := createTestDriver(t)
  1085  	destroy := func() { destroyDriver(t, driver) }
  1086  	defer recoverTest(t, destroy)
  1087  
  1088  	// matches order of Java tests
  1089  	subscriptionsBasic_canReleaseSubscription(t, driver)
  1090  	subscriptionsBasic_shouldRespectMaxDocCountInBatch(t, driver)
  1091  	subscriptionsBasic_shouldStreamAllDocumentsAfterSubscriptionCreation(t, driver)
  1092  	subscriptionsBasic_shouldRespectCollectionCriteria(t, driver)
  1093  	subscriptionsBasic_willAcknowledgeEmptyBatches(t, driver)
  1094  
  1095  	// subscriptionsBasic_shouldStopPullingDocsAndCloseSubscriptionOnSubscriberErrorByDefault(t, driver)
  1096  
  1097  	subscriptionsBasic_disposingOneSubscriptionShouldNotAffectOnNotificationsOfOthers(t, driver)
  1098  	subscriptionsBasic_shouldPullDocumentsAfterBulkInsert(t, driver)
  1099  	//subscriptionsBasic_canSetToIgnoreSubscriberErrors(t, driver)
  1100  	subscriptionsBasic_ravenDB_3452_ShouldStopPullingDocsIfReleased(t, driver)
  1101  	subscriptionsBasic_canDeleteSubscription(t, driver)
  1102  
  1103  	subscriptionsBasic_shouldThrowOnAttemptToOpenAlreadyOpenedSubscription(t, driver)
  1104  
  1105  	subscriptionsBasic_shouldThrowWhenOpeningNoExistingSubscription(t, driver)
  1106  	subscriptionsBasic_shouldSendAllNewAndModifiedDocs(t, driver)
  1107  	subscriptionsBasic_ravenDB_3453_ShouldDeserializeTheWholeDocumentsAfterTypedSubscription(t, driver)
  1108  }