[ANN] php sdk 2.3.0

what package manager you use? we build RPMs and DEBs also. Lets fix your package manager together :slight_smile:

This is how we do it for FreeBSD for example:

https://aur.archlinux.org/packages/libcouchbase/

But why the release on github are not usable ?

Because release process includes generation of metadata (which usually could be gathered from git if you are working in cloned repository). This information lives in file ./packaging/distinfo/distinfo.cmake, and libcouchbase-2.7.2.tag.gz from couchbase site includes it. Github cannot do it obviously, because all it does is to run git archive. So this template would never instantiated:

So please inform AUR maintainers to use official tarballs

Well then this file should be commit and then the repository tagged so.
In PHP when we have a version in file, we update the file (manually or with a process), we commit the file with the last version THEN we tag.

this file is explicitly not commited to the respository, because it is part of the released package, developers are using git to work with project. I’ve updated AUR project page with advice to use proper release package.

The actual version information inside the library is generated from git describe. When you download a tarball from github, that process is missing.

Generating version info from Git ensures that the version is always what it claims to be.

We have a special make dist target in libcouchbase that ensures the version information is contained within the library.

Sorry if I’m repeating any info already mentioned in the thread!

We also have problems in our unit tests with the now final classes which can’t be mocked any more. In my view, there should be at least interfaces if it is absolutely necessary to declare the classes final: Copying the declaration of every single method of a SDK class in a custom proxy class and keeping this proxy manually up to date (including phpdoc) is a unnecessary work. It renders many advantages of the type system unused.

Either we develop against an interface of the PHP SDK instead of the concrete SDK class. Then PHP automatically checks wether our mock class still fulfills the contract of the interface and the IDE shows the documentation of the interface and takes the types from the phpdoc there. Or we do it like before: Use PHPunit to mock the slow database accesses away the fast and convenient.

The mocking does not work with the final classes. The interfaces don’t exist and we don’t want to maintain them: That would be like maintaining the proxy class. So we either have snail-like unit tests running all against the same database or a bunch of unnecessary work. Could you please consider offering any kind of solution for this topic?

@kstorch so if I just make classes not final, but still continue declaring methods as final, would it solve your problem?

Unfortunately not. See https://phpunit.de/manual/current/en/test-doubles.html:

Please note that final, private and static methods cannot be stubbed or mocked. They are ignored by PHPUnit’s test double functionality and retain their original behavior.

When to declare classes final explains pretty good why it is in principle a good idea to make the PHP SDK classes final. But is also pretty clear, why it is in practice not a good idea to make them final:

Final classes only work effectively under following assumptions:

  1. There is an abstraction (interface) that the final class implements
  2. All of the public API of the final class is part of that interface

If one of these two pre-conditions is missing, then you will likely reach a point in time when you will make the class extensible, as your code is not truly relying on abstractions.

And that is the point we reached - except we cannot make the classes extensible ourselves.

But the real problem you are solving is to run your tests without Couchbase Server? Right?

Yes, but for several reasons:

  • Database is access is quite slow. Unit tests should be fast.
  • We can not spin up a new Couchbase Cluster Instance for every (possibly parallel) run of the test suite. Emptying buckets is a time consuming test preparation.
  • In most cases, it is more convenient to produce the indirect input for the system under test via replacing the Couchbase object instead of writing the input in the Couchbase bucket. Especially because parallel tests may expect different data in the same database/bucket (see above).
  • Sometimes it is helpful to check what the system under test does with other systems - here Couchbase. That’s when the mock is really used as mock instead as stub. For example, our custom Query class holds the bucket which it is meant to be executed on as attribute. We want to test that our Couchbase wrapper gets the right bucket for the query if we execute it.

I’m planning to integrate with our CouchbaseMock library, which was designed for this purpose. Essentially it is mini Couchbase Cluster, with extra features allowing you simulate different operational conditions.

1 Like

Great, that sounds like solving our problem. To answer your question above perhaps a bit more focused: Yes, we just want to mock the Couchbase classes for testing purposes, not to “really” extend them.

Cool. Thank you for feedback. I will post here and in release notes when we’ll get the integration.